118 lines
5.2 KiB
TypeScript
118 lines
5.2 KiB
TypeScript
import { test, expect } from '@playwright/test'
|
|
import { imhotep } from 'imhotep-playwright'
|
|
import { loadFixtureInPage, waitForFixtureReady } from './harness.js'
|
|
|
|
async function fixtureUrl(category: string): Promise<string> {
|
|
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)
|
|
})
|
|
})
|