import { test, expect } from '@playwright/test' import { imhotep } from 'imhotep-playwright' import { loadFixtureInPage, waitForFixtureReady } from './harness.js' async function fixtureUrl(category: string): Promise { const { resolveFixturePage } = await import('./harness.js') return 'file://' + resolveFixturePage(category) } test.describe('E2E: Frames', () => { test('element inside positioned ancestor resolves correct frame', async ({ page }) => { const ui = await imhotep(page) await page.goto(await fixtureUrl('frames')) await waitForFixtureReady(page) const ancestorData = await ui.extract('[data-testid="positioned-ancestor"]') const childData = await ui.extract('[data-testid="nested-absolute"]') expect(Array.isArray(ancestorData)).toBe(true) expect(Array.isArray(childData)).toBe(true) const ancestorRect = (ancestorData as any[])[0].rect const childRect = (childData as any[])[0].rect // Absolute child should be positioned within ancestor bounds // Use approximate checks since padding and positioning offsets vary expect(childRect.x).toBeGreaterThanOrEqual(ancestorRect.x - 5) expect(childRect.x + childRect.width).toBeLessThanOrEqual(ancestorRect.x + ancestorRect.width + 5) expect(childRect.y + childRect.height).toBeLessThanOrEqual(ancestorRect.y + ancestorRect.height + 5) }) test('element inside scroll container maintains geometry in viewport', async ({ page }) => { const ui = await imhotep(page) await page.goto(await fixtureUrl('frames')) await waitForFixtureReady(page) const scrollContainerData = await ui.extract('[data-testid="scroll-container"]') const scrollItemData = await ui.extract('[data-testid="scroll-item"]') const containerRect = (scrollContainerData as any[])[0].rect const itemRect = (scrollItemData as any[])[0].rect // Scroll item should be within the scroll container bounds expect(itemRect.x).toBeGreaterThanOrEqual(containerRect.x) expect(itemRect.y).toBeGreaterThanOrEqual(containerRect.y) }) test('element inside named grid area has correct grid geometry', async ({ page }) => { const ui = await imhotep(page) await page.goto(await fixtureUrl('frames')) await waitForFixtureReady(page) const gridData = await ui.extract('[data-testid="grid-container"]') const headerData = await ui.extract('[data-testid="grid-header"]') const sidebarData = await ui.extract('[data-testid="grid-sidebar"]') const contentData = await ui.extract('[data-testid="grid-content"]') const footerData = await ui.extract('[data-testid="grid-footer"]') const gridRect = (gridData as any[])[0].rect const headerRect = (headerData as any[])[0].rect const sidebarRect = (sidebarData as any[])[0].rect const contentRect = (contentData as any[])[0].rect const footerRect = (footerData as any[])[0].rect // Header should span full width at top (accounting for grid padding) expect(headerRect.x).toBeGreaterThanOrEqual(gridRect.x) expect(headerRect.x).toBeLessThanOrEqual(gridRect.x + 20) expect(headerRect.width).toBeLessThanOrEqual(gridRect.width) expect(headerRect.width).toBeGreaterThanOrEqual(gridRect.width - 40) expect(headerRect.y).toBeGreaterThanOrEqual(gridRect.y) expect(headerRect.y).toBeLessThanOrEqual(gridRect.y + 20) // Sidebar should be left of content expect(sidebarRect.x + sidebarRect.width).toBeLessThanOrEqual(contentRect.x + 5) // Footer should span full width at bottom expect(footerRect.x).toBeGreaterThanOrEqual(gridRect.x) expect(footerRect.x).toBeLessThanOrEqual(gridRect.x + 20) expect(footerRect.width).toBeLessThanOrEqual(gridRect.width) expect(footerRect.width).toBeGreaterThanOrEqual(gridRect.width - 40) expect(footerRect.y).toBeGreaterThanOrEqual(contentRect.y + contentRect.height) }) test('fixed element is positioned relative to viewport', async ({ page }) => { const ui = await imhotep(page) await page.goto(await fixtureUrl('frames')) await waitForFixtureReady(page) const fixedData = await ui.extract('[data-testid="fixed-box"]') const fixedRect = (fixedData as any[])[0].rect // Fixed element should be near top-right of viewport expect(fixedRect.x).toBeGreaterThan(600) expect(fixedRect.y).toBeLessThanOrEqual(40) expect(fixedRect.width).toBe(100) expect(fixedRect.height).toBe(100) }) test('containing block child respects parent padding offset', async ({ page }) => { const ui = await imhotep(page) await page.goto(await fixtureUrl('frames')) await waitForFixtureReady(page) const parentData = await ui.extract('[data-testid="containing-block"]') const childData = await ui.extract('[data-testid="absolute-child"]') const parentRect = (parentData as any[])[0].rect const childRect = (childData as any[])[0].rect // Child is absolutely positioned with top:10px left:10px relative to parent's padding edge // The exact offset depends on the parent's viewport position; verify relative offset expect(childRect.x).toBeGreaterThanOrEqual(parentRect.x) expect(childRect.x).toBeLessThanOrEqual(parentRect.x + 40) expect(childRect.y).toBeGreaterThanOrEqual(parentRect.y) expect(childRect.y).toBeLessThanOrEqual(parentRect.y + 40) }) })