import { expect, test } from "@playwright/test"; const AxeBuilder = require("@axe-core/playwright").default; const blogUrl = process.env.TEST_BLOG_URL || "http://community-works-collaborative.test/blog/"; test.describe("blog page", () => { test("desktop: Blog title, post grid, no inner-page hero, sidebar", async ({ page, }) => { const pageErrors = []; page.on("pageerror", (err) => pageErrors.push(err.message)); await page.setViewportSize({ width: 1280, height: 900 }); await page.goto(blogUrl); // No inner-page hero. expect(await page.locator(".page-hero").count()).toBe(0); // Page title is "Blog". const heading = page.locator(".post-list__h1").first(); await expect(heading).toBeVisible(); await expect(heading).toHaveText("Blog"); // Post grid renders at least one card. const posts = page.locator(".post-list__post"); const postCount = await posts.count(); expect(postCount).toBeGreaterThanOrEqual(1); // First card: image, title link, byline. const firstCard = posts.first(); await expect(firstCard.locator(".post-list__img img")).toBeVisible(); await expect(firstCard.locator(".post-list__title")).toBeVisible(); await expect(firstCard.locator(".post-list__byline")).toBeVisible(); // First card has a "Read more" link. const readMore = firstCard.locator(".post-list__read-more"); await expect(readMore).toBeVisible(); await expect(readMore).toHaveText(/^Read more\s*\S+$/); await expect(readMore).toHaveAttribute("href", /\/[a-z0-9-]+\/?$/); // First card does NOT have a categories row or an excerpt. expect(await firstCard.locator(".post-list__cats").count()).toBe(0); expect(await firstCard.locator(".post-list__excerpt").count()).toBe(0); // Sidebar renders. await expect(page.locator("#secondary, .sidebar, aside").first()).toBeAttached(); // No JS errors. expect(pageErrors).toEqual([]); }); test("mobile 402: single-column grid, no horizontal overflow", async ({ page, }) => { await page.setViewportSize({ width: 402, height: 874 }); await page.goto(blogUrl); const heading = page.locator(".post-list__h1").first(); await expect(heading).toBeVisible(); const headingBox = await heading.boundingBox(); const block = page.locator(".post-list").first(); const blockBox = await block.boundingBox(); expect(headingBox).not.toBeNull(); expect(blockBox).not.toBeNull(); expect(headingBox.x + headingBox.width).toBeLessThanOrEqual(402 + 3); expect(blockBox.x + blockBox.width).toBeLessThanOrEqual(402 + 3); }); test("mobile 320: nothing clips horizontally", async ({ page }) => { await page.setViewportSize({ width: 320, height: 800 }); await page.goto(blogUrl); const block = page.locator(".post-list").first(); await expect(block).toBeVisible(); const blockBox = await block.boundingBox(); expect(blockBox.x + blockBox.width).toBeLessThanOrEqual(320 + 3); }); test("axe: no violations", async ({ page }, testInfo) => { await page.setViewportSize({ width: 1280, height: 900 }); await page.goto(blogUrl); const results = await new AxeBuilder({ page }) .withTags([ "wcag2a", "wcag2aa", "wcag21a", "wcag21aa", "wcag22a", "wcag22aa", ]) .analyze(); await testInfo.attach("accessibility-scan-results", { body: JSON.stringify(results, null, 2), contentType: "application/json", }); expect(results.violations).toEqual([]); }); });