e2e/issue-sidebar-containment.spec.ts
Rama main · réplica de lectura del repositorio original.
import { test, expect } from "@playwright/test";
import { createTestApi, loginAsDefault, waitForPageText } from "./helpers";
import type { TestApiClient } from "./fixtures";
// MUL-8100: absolutely positioned content inside the issue's right sidebar
// (the execution log's `sr-only` status labels) must stay clipped by the
// sidebar's own scroller. When it resolved against an ancestor outside the
// scroller, it stretched the surrounding panel's scroll height; wheeling past
// the end of the comments then scrolled the whole issue detail up, leaving a
// blank band at the bottom.
test.describe("Issue detail sidebar containment", () => {
let api: TestApiClient;
test.beforeEach(async () => {
api = await createTestApi();
});
test.afterEach(async () => {
await api?.cleanup();
});
test("absolutely positioned sidebar content does not grow the outer panels", async ({ page }) => {
// Short window so the sidebar overflows, like a long execution log does.
await page.setViewportSize({ width: 1440, height: 520 });
const title = "E2E sidebar containment " + Date.now();
const issue = await api.createIssue(title);
const slug = await loginAsDefault(page);
await page.goto(`/${slug}/issues/${issue.id}`, { waitUntil: "domcontentloaded" });
await waitForPageText(page, title);
await expect(page.locator("text=Properties")).toBeVisible();
const result = await page.evaluate(() => {
const sidebar = document.querySelector<HTMLElement>("[data-right-sidebar-panel] > div > div")!;
const content = sidebar.firstElementChild as HTMLElement;
// Mirror an execution-log row far below the fold: an `sr-only` label
// (position: absolute) inside non-positioned flex rows.
const row = document.createElement("div");
row.className = "flex overflow-hidden";
row.style.marginTop = "1500px";
const label = document.createElement("span");
label.className = "sr-only";
label.textContent = "Completed";
row.appendChild(label);
content.appendChild(row);
// Every scroller that wraps the whole detail (resizable panels, the
// page canvas) must stay exactly as tall as its box.
const grown: string[] = [];
for (let el = sidebar.parentElement; el; el = el.parentElement) {
const overflowY = getComputedStyle(el).overflowY;
if (overflowY === "visible") continue;
if (el.scrollHeight > el.clientHeight + 1) {
grown.push(`${el.tagName}.${el.className} ${el.scrollHeight}>${el.clientHeight}`);
}
}
return { containedBySidebar: label.offsetParent === sidebar, grown };
});
expect(result.containedBySidebar).toBe(true);
expect(result.grown).toEqual([]);
});
});