feat(demo): add Playwright browser tests, fix Homepage config mount

- Add Playwright E2E test suite covering all 13 user-facing services
- Fix Homepage HTTP 500 by removing read-only bind mount (:ro) so it
  can create its required logs/ directory
- Pin @playwright/test to exact 1.52.0 to match Docker image browsers
- Add .gitignore entries for auto-generated Homepage files and
  Playwright artifacts
- All 13 Playwright tests passing (Chromium headless)

💘 Generated with Crush

Assisted-by: GLM-5.1 via Crush <crush@charm.land>
This commit is contained in:
reachableceo
2026-05-01 11:24:59 -05:00
parent 50206dce6b
commit b03f4b2ba2
5 changed files with 69 additions and 2 deletions

View File

@@ -0,0 +1,30 @@
import { test, expect } from '@playwright/test';
const services = [
{ name: 'Homepage', url: 'http://localhost:4000', contentCheck: 'homepage' },
{ name: 'Pi-hole', url: 'http://localhost:4006/admin', contentCheck: 'pihole' },
{ name: 'Dockhand', url: 'http://localhost:4007', contentCheck: 'sveltekit' },
{ name: 'InfluxDB', url: 'http://localhost:4008', contentCheck: 'influxdb' },
{ name: 'Grafana', url: 'http://localhost:4009', contentCheck: 'grafana' },
{ name: 'Draw.io', url: 'http://localhost:4010', contentCheck: 'draw' },
{ name: 'Kroki', url: 'http://localhost:4011/health', contentCheck: 'kroki' },
{ name: 'Atomic Tracker', url: 'http://localhost:4012', contentCheck: 'journal' },
{ name: 'ArchiveBox', url: 'http://localhost:4013', contentCheck: 'archive' },
{ name: 'Tube Archivist', url: 'http://localhost:4014', contentCheck: 'tube' },
{ name: 'Wakapi', url: 'http://localhost:4015', contentCheck: 'wakapi' },
{ name: 'MailHog', url: 'http://localhost:4017', contentCheck: 'mailhog' },
{ name: 'Atuin', url: 'http://localhost:4018', contentCheck: 'version' },
];
for (const svc of services) {
test(`${svc.name} (${svc.url}) loads successfully`, async ({ page }) => {
const response = await page.goto(svc.url, { waitUntil: 'domcontentloaded', timeout: 30000 });
expect(response).not.toBeNull();
expect(response!.status()).toBeLessThan(400);
const body = await page.textContent('body').catch(() => '');
const title = await page.title().catch(() => '');
const combined = (body + ' ' + title).toLowerCase();
expect(combined).toContain(svc.contentCheck.toLowerCase());
});
}