Files
Lucas WintherandClaude Sonnet 5.5 994f41558c test(e2e): cover sparse content
Second webServer builds fixtures/sparse (no sources) on 4379; third-party allow-list
now derives from the configured servers; the embed test re-checks blocked requests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-09 09:43:34 +01:00

63 lines
2.6 KiB
TypeScript

import { expect, test, type Page } from '@playwright/test';
import { blockThirdParty } from './helpers.ts';
// fixtures/sparse: one project, no items, no issues, no external sources (see playwright.config.ts).
test.use({ baseURL: 'http://localhost:4379' });
test.beforeEach(async ({ page }) => {
await blockThirdParty(page);
});
const PAGES = ['/', '/work/', '/off-the-clock/', '/off-the-clock/issues/', '/everything/', '/simple/'];
// Visible containers with neither text nor a link/image/svg/media/control inside.
async function emptyBoxes(page: Page): Promise<string[]> {
return page.evaluate(() => {
const out: string[] = [];
const sel = 'section, article, aside, nav, ul, ol, dl, [class*="card"], [class*="strip"], [class*="now"], [class*="wall"], [class*="box"]';
for (const el of document.querySelectorAll<HTMLElement>(sel)) {
if (el.closest('template, script, [hidden]') || !el.getClientRects().length) continue;
const cs = getComputedStyle(el);
if (cs.visibility === 'hidden' || cs.display === 'none') continue;
const text = (el.innerText ?? '').trim();
const content = el.querySelector('a, button, img, svg, canvas, video, audio, iframe, input, picture');
if (!text && !content) {
const id = el.id ? `#${el.id}` : '';
out.push(`${el.tagName.toLowerCase()}${id}.${el.className}`);
}
}
return out;
});
}
for (const path of PAGES) {
test(`${path} renders cleanly`, async ({ page }) => {
const res = await page.goto(path);
expect(res!.status()).toBe(200);
const text = await page.locator('body').innerText();
expect(text).not.toMatch(/\bundefined\b|\bnull\b|\bNaN\b|\[object/);
expect(await emptyBoxes(page)).toEqual([]);
await expect(page.locator('h1, h2').first()).toBeVisible();
});
}
test('personal side shows its warm empty line, with no cards or writing', async ({ page }) => {
await page.goto('/off-the-clock/');
await expect(page.locator('[data-wall-card]')).toHaveCount(0);
await expect(page.getByText('Nothing pinned up yet. The first few things are on their way.')).toBeVisible();
await expect(page.getByText(/Latest writing/i)).toHaveCount(0);
});
test('no writing boxes or "Latest writing" anywhere', async ({ page }) => {
for (const path of PAGES) {
await page.goto(path);
await expect(page.getByText(/Latest writing/i), path).toHaveCount(0);
await expect(page.locator('[class*="writing"]:visible'), path).toHaveCount(0);
}
});
test('the work side still shows its one project', async ({ page }) => {
await page.goto('/work/');
await expect(page.locator('a[href="/work/fixture-dashboard/"]').first()).toBeVisible();
});