From 998619fa3fcbe5350c2f961294f2f7dd2a0a8950 Mon Sep 17 00:00:00 2001 From: Keith Solomon Date: Wed, 1 Jul 2026 11:13:34 -0500 Subject: [PATCH] Add Playwright coverage for inner page layout at all viewports --- page.php | 11 +-- static/dist/theme.css | 23 ------- tests/inner-page.spec.js | 125 ++++++++++++++++++++++++++++++++++ views/partials/page-intro.php | 2 +- 4 files changed, 132 insertions(+), 29 deletions(-) create mode 100644 tests/inner-page.spec.js diff --git a/page.php b/page.php index 7697eeb..a49ba0e 100644 --- a/page.php +++ b/page.php @@ -22,13 +22,14 @@ if ( hasSidebar() ) { ?>
+
= 48rem) { @@ -1809,11 +1796,6 @@ line-height: var(--tw-leading, var(--text-6xl--line-height)); } - .lg\:text-lg { - font-size: var(--text-lg); - line-height: var(--tw-leading, var(--text-lg--line-height)); - } - .lg\:text-xl { font-size: var(--text-xl); line-height: var(--tw-leading, var(--text-xl--line-height)); @@ -1893,11 +1875,6 @@ font-size: var(--text-7xl); line-height: var(--tw-leading, var(--text-7xl--line-height)); } - - .xl\:text-xl { - font-size: var(--text-xl); - line-height: var(--tw-leading, var(--text-xl--line-height)); - } } @media (width >= 96rem) { diff --git a/tests/inner-page.spec.js b/tests/inner-page.spec.js new file mode 100644 index 0000000..1b68273 --- /dev/null +++ b/tests/inner-page.spec.js @@ -0,0 +1,125 @@ +import { expect, test } from "@playwright/test"; + +const pageUrl = + process.env.TEST_PAGE_URL || + "http://community-works-collaborative.test/sample-page/"; + +const getBox = async (locator) => { + const box = await locator.boundingBox(); + expect(box).not.toBeNull(); + return box; +}; + +const expectNear = (actual, expected, tolerance = 3) => { + expect(Math.abs(actual - expected)).toBeLessThanOrEqual(tolerance); +}; + +test.describe("inner page layout", () => { + test("desktop: hero, intro, body render in order with the new media layers", async ({ + page, + }) => { + const pageErrors = []; + page.on("pageerror", (err) => pageErrors.push(err.message)); + + await page.setViewportSize({ width: 1280, height: 900 }); + await page.goto(pageUrl); + + const hero = page.locator(".page-hero").first(); + const intro = page.locator(".page-intro").first(); + const content = page.locator(".entry-content").first(); + + await expect(hero).toBeVisible(); + await expect(intro).toBeVisible(); + await expect(content).toBeVisible(); + + // Order check: hero, then intro, then content. + const heroBox = await getBox(hero); + const introBox = await getBox(intro); + const contentBox = await getBox(content); + + expect(heroBox.y).toBeLessThan(introBox.y); + expect(introBox.y).toBeLessThan(contentBox.y); + + // Heading is rendered inside the hero. + await expect(hero.locator("h1").first()).toBeVisible(); + + // Intro is centered and capped at the max-w-3xl width. + const introInner = intro.locator(".content-wrapper").first(); + const introInnerBox = await getBox(introInner); + expect(introInnerBox.width).toBeLessThanOrEqual(768 + 3); + + // Page renders without JS errors. + expect(pageErrors).toEqual([]); + }); + + test("mobile 402: hero, intro, body order and intro width", async ({ + page, + }) => { + const pageErrors = []; + page.on("pageerror", (err) => pageErrors.push(err.message)); + + await page.setViewportSize({ width: 402, height: 874 }); + await page.goto(pageUrl); + + const hero = page.locator(".page-hero").first(); + const intro = page.locator(".page-intro").first(); + const content = page.locator(".entry-content").first(); + + await expect(hero).toBeVisible(); + await expect(intro).toBeVisible(); + await expect(content).toBeVisible(); + + const heroBox = await getBox(hero); + const introBox = await getBox(intro); + const contentBox = await getBox(content); + + expect(heroBox.y).toBeLessThan(introBox.y); + expect(introBox.y).toBeLessThan(contentBox.y); + + // Intro fits within the mobile viewport. + const introInner = intro.locator(".content-wrapper").first(); + const introInnerBox = await getBox(introInner); + expect(introInnerBox.x + introInnerBox.width).toBeLessThanOrEqual( + 402 + 3, + ); + + // No JS errors. + expect(pageErrors).toEqual([]); + }); + + test("mobile 320: nothing clips horizontally", async ({ page }) => { + await page.setViewportSize({ width: 320, height: 800 }); + await page.goto(pageUrl); + + const hero = page.locator(".page-hero").first(); + const intro = page.locator(".page-intro").first(); + + await expect(hero).toBeVisible(); + await expect(intro).toBeVisible(); + + const heroBox = await getBox(hero); + const introBox = await getBox(intro); + + expect(heroBox.x + heroBox.width).toBeLessThanOrEqual(320 + 3); + expect(introBox.x + introBox.width).toBeLessThanOrEqual(320 + 3); + }); + + test("mobile 767: layout still holds before the desktop breakpoint", async ({ + page, + }) => { + await page.setViewportSize({ width: 767, height: 900 }); + await page.goto(pageUrl); + + const hero = page.locator(".page-hero").first(); + const intro = page.locator(".page-intro").first(); + + await expect(hero).toBeVisible(); + await expect(intro).toBeVisible(); + + const heroBox = await getBox(hero); + const introBox = await getBox(intro); + + expect(heroBox.x + heroBox.width).toBeLessThanOrEqual(767 + 3); + expect(introBox.x + introBox.width).toBeLessThanOrEqual(767 + 3); + }); +}); diff --git a/views/partials/page-intro.php b/views/partials/page-intro.php index 5d0cf37..a828c00 100644 --- a/views/partials/page-intro.php +++ b/views/partials/page-intro.php @@ -18,7 +18,7 @@ if ( ! $intro ) { ?>
-
+