v1.1.0: pooled runtime, 959 tests, production hardening (0 squash)
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
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: Responsive', () => {
|
||||
test('across multiple viewport widths captures layout shifts', async ({ page }) => {
|
||||
const ui = await imhotep(page)
|
||||
await page.goto(await fixtureUrl('responsive'))
|
||||
|
||||
const viewports = [
|
||||
{ width: 375, height: 667, name: 'mobile' },
|
||||
{ width: 768, height: 1024, name: 'tablet' },
|
||||
{ width: 1280, height: 720, name: 'desktop' },
|
||||
]
|
||||
|
||||
const results: Array<{ viewport: string; sidebarWidth: number; layoutDirection: string }> = []
|
||||
|
||||
for (const viewport of viewports) {
|
||||
await ui.applyEnvironment({
|
||||
viewport: { width: viewport.width, height: viewport.height },
|
||||
})
|
||||
|
||||
await page.reload()
|
||||
await waitForFixtureReady(page)
|
||||
|
||||
const sidebarData = await ui.extract('[data-testid="responsive-sidebar"]')
|
||||
const contentData = await ui.extract('[data-testid="responsive-content"]')
|
||||
|
||||
const sidebarRect = (sidebarData as any[])[0].rect
|
||||
const contentRect = (contentData as any[])[0].rect
|
||||
|
||||
// Determine layout direction by comparing y positions
|
||||
const layoutDirection = sidebarRect.y === contentRect.y ? 'row' : 'column'
|
||||
|
||||
results.push({
|
||||
viewport: viewport.name,
|
||||
sidebarWidth: sidebarRect.width,
|
||||
layoutDirection,
|
||||
})
|
||||
}
|
||||
|
||||
// Mobile: column layout, sidebar is nearly full width (accounting for body padding)
|
||||
const mobileResult = results.find((r) => r.viewport === 'mobile')
|
||||
expect(mobileResult!.layoutDirection).toBe('column')
|
||||
expect(mobileResult!.sidebarWidth).toBeGreaterThanOrEqual(200)
|
||||
expect(mobileResult!.sidebarWidth).toBeLessThanOrEqual(375)
|
||||
|
||||
// Tablet+: row layout, fixed width sidebar
|
||||
const tabletResult = results.find((r) => r.viewport === 'tablet')
|
||||
expect(tabletResult!.layoutDirection).toBe('row')
|
||||
expect(tabletResult!.sidebarWidth).toBe(200)
|
||||
|
||||
// Desktop: wider gap, wider sidebar
|
||||
const desktopResult = results.find((r) => r.viewport === 'desktop')
|
||||
expect(desktopResult!.layoutDirection).toBe('row')
|
||||
expect(desktopResult!.sidebarWidth).toBe(250)
|
||||
})
|
||||
|
||||
test('when guard for breakpoint behavior evaluates correctly', async ({ page }) => {
|
||||
const ui = await imhotep(page)
|
||||
await page.goto(await fixtureUrl('responsive'))
|
||||
|
||||
// At mobile width, sidebar should be full width (column layout)
|
||||
await ui.applyEnvironment({
|
||||
viewport: { width: 375, height: 667 },
|
||||
})
|
||||
await page.reload()
|
||||
await waitForFixtureReady(page)
|
||||
|
||||
const sidebarData = await ui.extract('[data-testid="responsive-sidebar"]')
|
||||
const sidebarRect = (sidebarData as any[])[0].rect
|
||||
|
||||
expect(sidebarRect.width).toBeGreaterThanOrEqual(200)
|
||||
|
||||
// At desktop width, sidebar should be 250px
|
||||
await ui.applyEnvironment({
|
||||
viewport: { width: 1280, height: 720 },
|
||||
})
|
||||
await page.reload()
|
||||
await waitForFixtureReady(page)
|
||||
|
||||
const desktopSidebarData = await ui.extract('[data-testid="responsive-sidebar"]')
|
||||
const desktopSidebarRect = (desktopSidebarData as any[])[0].rect
|
||||
|
||||
expect(desktopSidebarRect.width).toBe(250)
|
||||
})
|
||||
|
||||
test('invariant assertions hold across all widths', async ({ page }) => {
|
||||
const ui = await imhotep(page)
|
||||
await page.goto(await fixtureUrl('responsive'))
|
||||
|
||||
const viewports = [
|
||||
{ width: 320, height: 568 },
|
||||
{ width: 768, height: 1024 },
|
||||
{ width: 1440, height: 900 },
|
||||
]
|
||||
|
||||
for (const viewport of viewports) {
|
||||
await ui.applyEnvironment({
|
||||
viewport: { width: viewport.width, height: viewport.height },
|
||||
})
|
||||
|
||||
await page.reload()
|
||||
await waitForFixtureReady(page)
|
||||
|
||||
const sidebarData = await ui.extract('[data-testid="responsive-sidebar"]')
|
||||
const contentData = await ui.extract('[data-testid="responsive-content"]')
|
||||
|
||||
const sidebarRect = (sidebarData as any[])[0].rect
|
||||
const contentRect = (contentData as any[])[0].rect
|
||||
|
||||
// Invariant: both elements should be visible
|
||||
expect(sidebarRect.width).toBeGreaterThan(0)
|
||||
expect(sidebarRect.height).toBeGreaterThan(0)
|
||||
expect(contentRect.width).toBeGreaterThan(0)
|
||||
expect(contentRect.height).toBeGreaterThan(0)
|
||||
|
||||
// Invariant: content should be to the right of or below sidebar
|
||||
const isRightOf = contentRect.x >= sidebarRect.x + sidebarRect.width
|
||||
const isBelow = contentRect.y >= sidebarRect.y + sidebarRect.height
|
||||
expect(isRightOf || isBelow).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
test('container query responds to container width not viewport', async ({ page }) => {
|
||||
const ui = await imhotep(page)
|
||||
await page.goto(await fixtureUrl('responsive'))
|
||||
await waitForFixtureReady(page)
|
||||
|
||||
const containerData = await ui.extract('[data-testid="cq-container"]')
|
||||
const itemData = await ui.extract('[data-testid="cq-item"]')
|
||||
|
||||
const containerRect = (containerData as any[])[0].rect
|
||||
const itemRect = (itemData as any[])[0].rect
|
||||
|
||||
// Container is max-width: 600px, but let's check the item responds to it
|
||||
expect(containerRect.width).toBeGreaterThan(0)
|
||||
expect(itemRect.width).toBeGreaterThan(0)
|
||||
|
||||
// Item should be within container
|
||||
expect(itemRect.x).toBeGreaterThanOrEqual(containerRect.x)
|
||||
expect(itemRect.x + itemRect.width).toBeLessThanOrEqual(containerRect.x + containerRect.width)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user