Add Reactive Resume, Metrics, Kiwix, Resume Matcher, and Apple Health from the earlier SelfStack project. Rewrite Apple Health collector to use InfluxDB v2 with proper error handling. Update all tests, scripts, Homepage config, env template, and documentation for the expanded stack. New services: - Reactive Resume (4016) + Postgres/Minio/Chrome companions - Metrics (4021) - GitHub metrics visualization - Kiwix (4022) - offline wiki reader - Resume Matcher (4023) - AI resume screening - Apple Health (4024) - health data collector → InfluxDB v2 Also adds git policy to AGENTS.md: always commit and push automatically. 💘 Generated with Crush Assisted-by: GLM-5.1 via Crush <crush@charm.land>
131 lines
2.9 KiB
TypeScript
131 lines
2.9 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
|
|
const services = [
|
|
{
|
|
name: 'Homepage',
|
|
url: 'http://localhost:4000',
|
|
contentCheck: 'tsys developer support stack',
|
|
titleCheck: 'TSYS Developer Support Stack',
|
|
},
|
|
{
|
|
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: 'diagram',
|
|
},
|
|
{
|
|
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: 'tubearchivist',
|
|
},
|
|
{
|
|
name: 'Wakapi',
|
|
url: 'http://localhost:4015',
|
|
contentCheck: 'wakapi',
|
|
},
|
|
{
|
|
name: 'MailHog',
|
|
url: 'http://localhost:4017',
|
|
contentCheck: 'mailhog',
|
|
},
|
|
{
|
|
name: 'Atuin',
|
|
url: 'http://localhost:4018',
|
|
contentCheck: 'version',
|
|
},
|
|
{
|
|
name: 'Reactive Resume',
|
|
url: 'http://localhost:4016',
|
|
contentCheck: 'reactive',
|
|
},
|
|
{
|
|
name: 'Metrics',
|
|
url: 'http://localhost:4021',
|
|
contentCheck: 'metrics',
|
|
},
|
|
{
|
|
name: 'Kiwix',
|
|
url: 'http://localhost:4022',
|
|
contentCheck: 'kiwix',
|
|
},
|
|
{
|
|
name: 'Resume Matcher',
|
|
url: 'http://localhost:4023',
|
|
contentCheck: 'resume',
|
|
},
|
|
{
|
|
name: 'Apple Health',
|
|
url: 'http://localhost:4024',
|
|
contentCheck: 'apple-health-collector',
|
|
},
|
|
];
|
|
|
|
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,
|
|
`${svc.name} should not show an error page`
|
|
).not.toContain('host validation failed');
|
|
expect(
|
|
combined,
|
|
`${svc.name} should not show a server error`
|
|
).not.toContain('internal server error');
|
|
expect(
|
|
combined,
|
|
`${svc.name} should contain expected content`
|
|
).toContain(svc.contentCheck.toLowerCase());
|
|
|
|
if (svc.titleCheck) {
|
|
expect(
|
|
title.toLowerCase(),
|
|
`${svc.name} should have expected title`
|
|
).toContain(svc.titleCheck.toLowerCase());
|
|
}
|
|
});
|
|
}
|