From 35302f72516eb22b8b61e34c1b6c6519dcd0ade6 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Thu, 15 Oct 2026 12:16:05 +0200 Subject: [PATCH] test: verify library image controls and isolate website config --- .../browser/agent-tab-image-stability.spec.ts | 33 ++++++++++--------- .../e2e/support/helpers/assistant-images.ts | 10 +++--- packages/website/vite.config.ts | 2 +- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/packages/app/e2e/browser/agent-tab-image-stability.spec.ts b/packages/app/e2e/browser/agent-tab-image-stability.spec.ts index 841314343f..d664c1dcf4 100644 --- a/packages/app/e2e/browser/agent-tab-image-stability.spec.ts +++ b/packages/app/e2e/browser/agent-tab-image-stability.spec.ts @@ -97,11 +97,11 @@ test("opens a timeline image in a zoomable lightbox", async ({ await openAssistantImageTimeline(page, imageAgent); await expectAssistantImageRendered(page, image); - await page.getByRole("button", { name: "Open image attachment" }).click(); + await page.getByRole("button", { name: image.alt }).click(); const lightboxImage = page.getByTestId("attachment-lightbox-image"); const canvas = page.getByTestId("attachment-lightbox-canvas"); await expect(lightboxImage).toBeVisible(); - await canvas.hover(); + await page.getByTestId("zoomable-viewport-toolbar").hover(); const transformedContent = canvas.locator(":scope > div").first(); const initialBox = await transformedContent.boundingBox(); const canvasBox = await canvas.boundingBox(); @@ -133,7 +133,7 @@ test("opens a timeline image in a zoomable lightbox", async ({ await expectAgentReadyToInterrupt(page); }); -test("reloading a timeline anchors near-tail assistant image growth", async ({ +test("reloading a timeline reserves image height without a load-time scroll jump", async ({ imageWorkspace: workspace, page, }) => { @@ -194,14 +194,15 @@ test("reloading a timeline anchors near-tail assistant image growth", async ({ } }; const inspect = () => { - const target = Array.from(document.querySelectorAll('[role="img"]')).find( - (element) => element.getAttribute("aria-label") === accessibleName, + const target = Array.from(document.querySelectorAll("img[alt]")).find( + (element) => element.getAttribute("alt") === accessibleName, ); if (!target || target === state.target) { record(); return; } state.target = target; + target.addEventListener("load", record, { once: true }); state.resizeObserver?.disconnect(); state.resizeObserver = new ResizeObserver(record); state.resizeObserver.observe(target); @@ -235,7 +236,6 @@ test("reloading a timeline anchors near-tail assistant image growth", async ({ await expectAssistantImageRendered(page, image); await page.reload(); await expectAssistantImageRendered(page, image); - await page.waitForTimeout(500); const events = await page.evaluate(() => { const state = ( @@ -246,16 +246,17 @@ test("reloading a timeline anchors near-tail assistant image growth", async ({ if (!state) throw new Error("Reload image geometry observer was not installed"); return state.events; }); - const geometryEvents = events as Array<{ height: number; scrollTop: number }>; - const initialGeometry = geometryEvents.find((event) => event.height > 0); - if (!initialGeometry) - throw new Error(`Image geometry was never measurable: ${JSON.stringify(events)}`); - const expandedGeometry = geometryEvents.find((event) => event.height > initialGeometry.height); - if (!expandedGeometry) - throw new Error(`Image geometry never expanded: ${JSON.stringify(events)}`); - expect(expandedGeometry.scrollTop, JSON.stringify(events)).toBeGreaterThan( - initialGeometry.scrollTop, - ); + const geometryEvents = events as Array<{ + complete: boolean; + height: number; + scrollTop: number; + }>; + const loadedIndex = geometryEvents.findIndex((event) => event.complete && event.height > 0); + expect(loadedIndex, JSON.stringify(events)).toBeGreaterThan(0); + const beforeLoad = geometryEvents[loadedIndex - 1]!; + const loaded = geometryEvents[loadedIndex]!; + expect(loaded.height).toBe(beforeLoad.height); + expect(loaded.scrollTop).toBe(beforeLoad.scrollTop); }); test("a real assistant PNG remains reachable through pagination and remount", async ({ diff --git a/packages/app/e2e/support/helpers/assistant-images.ts b/packages/app/e2e/support/helpers/assistant-images.ts index c4200c7c75..c9ca6d2ebf 100644 --- a/packages/app/e2e/support/helpers/assistant-images.ts +++ b/packages/app/e2e/support/helpers/assistant-images.ts @@ -124,7 +124,7 @@ export async function expectAssistantImageRendered( page: Page, image: AssistantImageFixture, ): Promise { - const rendered = page.getByRole("img", { name: image.alt }).first(); + const rendered = page.getByRole("button", { name: image.alt }).first(); await expect(rendered).toBeVisible({ timeout: 30_000 }); await expect .poll(async () => @@ -172,14 +172,14 @@ export async function expectAssistantImageNotMounted( page: Page, image: AssistantImageFixture, ): Promise { - await expect(page.getByRole("img", { name: image.alt })).toHaveCount(0); + await expect(page.getByRole("button", { name: image.alt })).toHaveCount(0); } export async function userPagesUntilAssistantImageRenders( page: Page, image: AssistantImageFixture, ): Promise { - const rendered = page.getByRole("img", { name: image.alt }); + const rendered = page.getByRole("button", { name: image.alt }); for (let attempt = 0; attempt < 10; attempt += 1) { if ((await rendered.count()) > 0) { await expectAssistantImageRendered(page, image); @@ -253,8 +253,8 @@ async function beginVisibleImageStabilityObservation( ); const imageTab = document.querySelector(`[data-testid="${tabTestId}"]`); if (imageTab?.getAttribute("aria-selected") !== "true") return; - const imageVisible = Array.from(document.querySelectorAll('[role="img"]')).some( - (element) => element.getAttribute("aria-label") === accessibleName && isVisible(element), + const imageVisible = Array.from(document.querySelectorAll("img[alt]")).some( + (element) => element.getAttribute("alt") === accessibleName && isVisible(element), ); record.missingSeen ||= !imageVisible; }; diff --git a/packages/website/vite.config.ts b/packages/website/vite.config.ts index 46dbc554de..d609be14bb 100644 --- a/packages/website/vite.config.ts +++ b/packages/website/vite.config.ts @@ -117,7 +117,7 @@ export default defineConfig((): UserConfig => { }, plugins: [ cloudflare({ viteEnvironment: { name: "ssr" } }), - tsConfigPaths(), + tsConfigPaths({ projects: [path.join(__dirname, "tsconfig.json")] }), tanstackStart({ router: { quoteStyle: "double",