Files
dogfather-universe/pruef-links.mjs
T
DogFatherGitandClaude Opus 5 3a8a52aa49 Test: kein interner Link zeigt ins Leere
Sammelt alle internen Links von 24 öffentlichen Seiten und prüft jedes
Ziel einmal gegen die echte Domain. Weiterleitungen (3xx, z.B. auf eine
Zugangswand) gelten als gültig, nur 4xx/5xx als toter Link.

Ergebnis: 41 Ziele, alle in Ordnung, 0 kaputt.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 15:06:36 +02:00

99 lines
4.1 KiB
JavaScript

/* =====================================================================
Zeigt irgendein interner Link ins Leere?
Ein toter Link in der Navigation oder im Text schickt Besucher auf die
404-Seite. Beim normalen Klicken merkt man das kaum -- man klickt ja
die Links, von denen man weiß, dass sie gehen. Dieser Test sammelt ALLE
internen Links von den öffentlichen Seiten ein und prüft für jedes Ziel
EINMAL, ob es wirklich existiert (kein 404/5xx).
Gegen die echte Domain, damit auch die serverseitige Auslieferung
(Weiterleitungen, Zugangswände) mitgeprüft wird.
Aufruf: node pruef-links.mjs
===================================================================== */
import { chromium } from "playwright";
const BASIS = "https://dogfather-universe.com";
/* Die öffentlich verlinkten Seiten -- von hier aus wird die Verlinkung
aufgesammelt. Unterseiten, die nur von diesen aus verlinkt sind, werden
über ihre Links automatisch mitgeprüft. */
const SEITEN = [
"/", "/dogfather.html", "/hasidog.html", "/manager.html", "/casper.html",
"/vanvan.html", "/tt-muddi.html", "/zeitreise.html", "/streamer.html",
"/community.html", "/stimmen.html", "/streamplan.html", "/team-modis.html",
"/team-scouts.html", "/creator.html", "/werte.html", "/bewerben.html",
"/kontakt.html", "/links.html", "/supporter.html", "/abonnieren.html",
"/medien-dogfather.html", "/medien-hasidog.html", "/medien-casper.html",
];
const browser = await chromium.launch();
/* 1. Alle internen Ziele einsammeln. */
const ziele = new Map(); // pfad -> Set der Seiten, die darauf verlinken
const seiteFehler = [];
for (const pfad of SEITEN) {
const seite = await browser.newPage();
try {
const antwort = await seite.goto(BASIS + pfad, { waitUntil: "domcontentloaded", timeout: 30000 });
if (!antwort || antwort.status() >= 400) {
seiteFehler.push(`${pfad} selbst -> ${antwort ? antwort.status() : "keine Antwort"}`);
}
const links = await seite.evaluate(() => {
return [...document.querySelectorAll('a[href]')]
.map((a) => a.getAttribute("href"))
.filter((h) => h && !h.startsWith("#") && !h.startsWith("mailto:") &&
!h.startsWith("tel:") && !h.startsWith("javascript:"));
});
for (const h of links) {
/* Nur interne Links prüfen. Externe (andere Domains) lassen wir aus
-- die kann diese Seite nicht garantieren, und sie ändern sich
außerhalb unserer Kontrolle. */
let url;
try { url = new URL(h, BASIS + pfad); } catch { continue; }
if (url.origin !== BASIS) continue;
const ziel = url.pathname + url.search;
if (!ziele.has(ziel)) ziele.set(ziel, new Set());
ziele.get(ziel).add(pfad);
}
} catch (e) {
seiteFehler.push(`${pfad} selbst -> ${String(e.message).slice(0, 40)}`);
}
await seite.close();
}
console.log(`\n${ziele.size} verschiedene interne Ziele von ${SEITEN.length} Seiten gesammelt.\n`);
/* 2. Jedes Ziel EINMAL prüfen. */
const pruefSeite = await browser.newPage();
let ok = 0;
const kaputt = [];
for (const [ziel, quellen] of [...ziele].sort()) {
try {
const a = await pruefSeite.goto(BASIS + ziel, { waitUntil: "commit", timeout: 20000 });
const code = a ? a.status() : 0;
/* < 400 gilt als in Ordnung -- auch Weiterleitungen (3xx) auf eine
Zugangswand sind ein gültiges Ziel, kein toter Link. */
if (code < 400) { ok++; }
else { kaputt.push({ ziel, code, quellen: [...quellen] }); }
} catch (e) {
kaputt.push({ ziel, code: String(e.message).slice(0, 30), quellen: [...quellen] });
}
}
await browser.close();
console.log(`===== ${ok} Ziele in Ordnung, ${kaputt.length} kaputt, ${seiteFehler.length} Seiten selbst fehlerhaft =====`);
if (seiteFehler.length) {
console.log("\nSeiten, die selbst nicht luden:");
for (const f of seiteFehler) console.log(" - " + f);
}
if (kaputt.length) {
console.log("\nTote Links (Ziel -> Code, verlinkt von):");
for (const k of kaputt) console.log(` - ${k.ziel} -> ${k.code} (von: ${k.quellen.join(", ")})`);
}
process.exitCode = kaputt.length || seiteFehler.length ? 1 : 0;