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]>
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
/* =====================================================================
|
||||
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;
|
||||
Reference in New Issue
Block a user