Ein Feature-Test zeigt grün – doch die Anwendung stürzt beim Nutzer ab. Diese frustrierende Situation kennen viele Entwickler. Besonders tückisch sind Fehler, die erst zur Laufzeit auftreten, obwohl alle Tests erfolgreich durchlaufen. Genau eine solche Situation erlebte ich kürzlich im Admin-Bereich eines Laravel-Pakets – und die Lösung lag nicht in einer einfachen Namenskorrektur, sondern in einem gezielten Test, der den Fehler bereits im Vorfeld aufdeckte.**
Warum manche Fehler Tests umgehen
Der Admin-Bereich des Pakets laravel-config-sso nutzt die Bibliothek Flux, die Icons über eine registry auflöst. Wird ein nicht existierender Icon-Name verwendet, wirft Flux zur Laufzeit eine Fehlermeldung:
Flux component [icon.ellipsis] does not exist.Die Ursache: Flux verwendet standardmäßig Heroicons, nicht Lucide. Entwickler greifen jedoch oft auf Lucide-Namen zurück, da diese geläufiger sind. Typische Verwechslungen sind:
ellipsis(Lucide) vs.ellipsis-horizontal(Heroicon)trash-2(Lucide) vs.trash(Heroicon)eye-off(Lucide) vs.eye-slash(Heroicon)
Doch warum wurde dieser Fehler nicht von den vorhandenen Feature-Tests erkannt?
Der blinde Fleck klassischer Tests
Die bestehende Testsuite prüfte die Admin-Route und bestätigte einen HTTP-Statuscode 200. Grün. Doch die echte Anwendung stürzte ab. Der Grund: Im headless Testumfeld rendert Flux Icons als Platzhalter ohne tatsächliche Überprüfung. Die Icon-Namen wurden nie aufgelöst, da die Testumgebung keine echte Flux-Integration benötigte.
Stellen Sie sich einen Rechtschreibprüfer vor, der nur beim Drucken des Dokuments aktiv wird – nicht während des Schreibens. Die Tests simulieren das Tippen, doch der Fehler wartet erst beim Drucken (also in der Produktion).
Ein statischer Test als Lösung
Um diesen Fehler künftig zu vermeiden, entwickelte ich einen Pest-Test, der die Blade-Dateien statisch analysiert und jeden Icon-Namen validiert. Der Test prüft, ob die verwendeten Icons tatsächlich in Fluxs Icon-Verzeichnis vorhanden sind:
$fluxIconStubs = base_path('vendor/livewire/flux/stubs/resources/views/flux/icon');
it('only references Flux icons that exist', function () use ($fluxIconStubs) {
expect(is_dir($fluxIconStubs))->toBeTrue("Flux icon stubs not found");
$view = file_get_contents(__DIR__.'/../../resources/views/livewire/sso-providers.blade.php');
// Statische Icon-Namen und dynamische Ausdrücke extrahieren
preg_match_all('/icon="([a-z][a-z0-9-]*)"/', $view, $static);
preg_match_all('/icon="\{\{(.+?)\}\}"/', $view, $dynamic);
$names = $static[1];
foreach ($dynamic[1] as $expression) {
preg_match_all("/'([a-z][a-z0-9-]*)'"/, $expression, $tokens);
$names = array_merge($names, $tokens[1]);
}
$names = array_values(array_unique($names));
expect($names)->not->toBeEmpty();
foreach ($names as $name) {
expect(is_file("{$fluxIconStubs}/{$name}.blade.php"))
->toBeTrue("Flux hat kein Icon [{$name}] – verwende einen gültigen Heroicon-Namen (Flux nutzt Heroicons, nicht Lucide).");
}
});Warum dieser Test funktioniert
- Direkter Zugriff auf die Quelle: Statt auf eine manuell gepflegte Liste von Icon-Namen zu verweisen, greift der Test direkt auf Fluxs Icon-Verzeichnis in
vendor/zu. So bleibt die Prüfung stets aktuell. - Unterstützung dynamischer Icons: Häufig übersehen werden Icons in bedingten Ausdrücken wie
{{ $cond ? 'eye-slash' : 'eye' }}. Der zweite reguläre Ausdruck erfasst auch diese Fälle. - Aktive Wissensvermittlung: Bei einem Fehlschlag gibt der Test einen klaren Hinweis: „Flux nutzt Heroicons, nicht Lucide.“ – eine Erinnerung für zukünftige Entwickler.
Praktische Anwendung und Nutzen
Der Nutzen dieses Tests zeigte sich bereits am selben Tag: Ein anderes Paket im selben Projekt fiel ebenfalls auf die Heroicon-vs-Lucide-Falle herein – konkret bei den Icons webhook, ellipsis und list, die nur in der Pro-Version von Flux enthalten sind. Ein solch präventiver Test wandelt einen „Crash in Produktion“ in ein „Fehler in der CI-Pipeline“ um – genau dort, wo er hingehört.
Wann dieser Testansatz sinnvoll ist
Nicht jeder Tippfehler rechtfertigt einen eigenen Test. Dieser Ansatz eignet sich besonders für Szenarien, in denen Tests die wahre Laufzeitumgebung nicht abbilden. Typische Beispiele:
- Komponenten, die im Testumfeld als Platzhalter gerendert werden,
- Adapter oder Bibliotheken, die in Tests gemockt werden,
- Umgebungsunterschiede zwischen Entwicklung und Produktion.
In solchen Fällen lohnt es sich, einen statischen Test zu schreiben, der direkt auf die Quelldateien zugreift – sei es eine Blade-Datei, eine Konfigurationsdatei oder eine Migration. Dies ist kostengünstiger, schneller und vermeidet das Problem der „No-Op“-Rendern in Tests.
Ein einfacher Grundsatz hilft bei der Entscheidung: Wenn ein Fehler nur bei einer vollständigen Ausführung auftritt, aber die Tests headless laufen, sollte der Fehler nicht in der CI-Pipeline gesucht werden. Stattdessen kann ein früherer Check über die Quelldateien den Fehler zuverlässig aufdecken – und das ohne zusätzliche Laufzeitkosten.**
KI-Zusammenfassung
Flux UI entegrasyonunda Heroicon ve Lucide ikon adlarını karıştırdığınızda üretimde çöküş yaşanır. Bu testi yazarak hataları CI sürecinde yakalayın ve sorunları erkenden çözün.