# End-to-End Test
Automatisierte End-to-End Tests sollen ganze Aktionen des Endusers simulieren und sind somit die Testart der geringsten Abstraktionsebene.
Sie können genutzt werden um ganze Workflows zu testen, wie z.B. Einkauf eines Produkts im Onlineshop.
# Laravel Dusk
Laravel bietet auch für End-to-End Tests ein Tool, namens Dusk (opens new window). Dies nutzt einen (headless) Browser unter der Haube. Es können Chrome und Firefox genutzt werden (opens new window).
# Dusk Chrome Plugin
Um die Test noch einfacher anfertigen zu können, gibt es ein Browserplugin für Chrome (opens new window), mit welchem man Aktionen aufzeichnen und sich anschließend als Dusk-Code ausgeben lassen kann.
# Magic Test for Laravel (ausgesetzt)
Als eine Alternative zu dem Dusk Chrome Plugin kann auch das Package Magic Test for Laravel (opens new window) genutzt werden.
⚠️ Da Magic Test momentan noch nicht zuverlässig funktioniert, wird es vorerst nicht genutzt.
# Debug Dusk Tests
Laravel Dusk ist ein mächtiges Tool für Browser-Testing, kann aber manchmal frustrierend zu debuggen sein. Dieser Guide hilft dir dabei, die häufigsten Probleme zu identifizieren und zu lösen.
# Allgemeine Debugging-Strategien
# 1. Screenshots bei Fehlern aktivieren
Füge automatische Screenshots bei Test-Fehlern hinzu:
// In deinem DuskTestCase oder einzelnen Tests
protected function tearDown(): void
{
if ($this->hasFailed()) {
$this->browse(function (Browser $browser) {
$browser->screenshot('failure-' . date('Y-m-d-H-i-s'));
});
}
parent::tearDown();
}
# 2. Browser-Console-Logs abrufen
// Console-Logs ausgeben
$browser->driver->manage()->getLog('browser');
// In deinem Test verwenden
$logs = $browser->driver->manage()->getLog('browser');
foreach ($logs as $log) {
echo $log['message'] . "\n";
}
# 3. Sichtbare Browser-Session
Teste mit sichtbarem Browser (nicht Headless):
// config/dusk.php oder DuskTestCase
$options = (new ChromeOptions)->addArguments([
'--disable-gpu',
'--no-sandbox',
'--window-size=1920,1080',
// '--headless', // Entferne diese Zeile
]);
# Dusk - Häufige Probleme und Lösungen
# Element nicht gefunden
Problem: Facebook\WebDriver\Exception\NoSuchElementException
Lösungsansätze:
// 1. Längere Wartezeiten
$browser->waitFor('@submit-button', 10);
// 2. Warten bis Element sichtbar ist
$browser->waitUntilVisible('@modal');
// 3. Auf Text warten
$browser->waitForText('Success message');
// 4. JavaScript-Rendering abwarten
$browser->pause(2000);
// 5. Explizite DOM-Checks
$browser->whenAvailable('@dynamic-content', function ($browser) {
$browser->click('@action-button');
});
# Element ist nicht interaktiv
Problem: Element is not clickable at point
Lösungen:
// 1. Scrollen zum Element
$browser->scrollTo('@element');
// 2. JavaScript-Click verwenden
$browser->script('document.querySelector("[dusk=\'submit-button\']").click()');
// 3. Warten bis Element klickbar ist
$browser->waitUntilEnabled('@submit-button');
// 4. Modals/Overlays prüfen
$browser->waitUntilMissing('@loading-overlay');
# Timing-Probleme
Problem: Tests sind instabil und schlagen manchmal fehl
Lösungen:
// 1. Implizite Waits erhöhen
$browser->driver->manage()->timeouts()->implicitlyWait(10);
// 2. Auf AJAX-Requests warten
$browser->waitForReload();
// 3. Auf CSS-Animationen warten
$browser->waitFor('.fade-in.show');
// 4. Custom Wait Conditions
$browser->waitUsing(5, 100, function () use ($browser) {
return $browser->element('@status')->getText() === 'Complete';
});
# Authentifizierung-Probleme
Problem: Login funktioniert nicht oder Session wird verloren
Lösungen:
// 1. Expliziten Login verwenden
$browser->loginAs(User::factory()->create());
// 2. Cookie-basierte Auth
$browser->visit('/login')
->type('email', 'user@example.com')
->type('password', 'password')
->press('Login')
->waitForLocation('/dashboard');
// 3. Session-Persistenz prüfen
$browser->assertAuthenticatedAs($user);
# Datenbankzustand-Probleme
Problem: Tests beeinflussen sich gegenseitig
Lösungen:
// 1. DatabaseTransactions verwenden
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ExampleTest extends DuskTestCase
{
use DatabaseTransactions;
}
// 2. Explizite Database-Resets
protected function setUp(): void
{
parent::setUp();
$this->artisan('migrate:refresh');
}
// 3. Isolierte Test-Daten
$browser->visit('/users/' . User::factory()->create()->id);
# Erweiterte Debugging-Techniken
# Browser-Entwicklertools nutzen
// Browser pausieren für manuelle Inspektion
$browser->pause();
// Breakpoint mit Ausgabe
$browser->dump(); // HTML-Quellcode
$browser->ddConsole(); // Console-Logs
# Custom Debugging-Methoden
// In deiner DuskTestCase Klasse
protected function debugElement(Browser $browser, string $selector): void
{
echo "=== Debugging Element: {$selector} ===\n";
// Element-Existenz prüfen
$exists = $browser->element($selector) !== null;
echo "Element exists: " . ($exists ? 'Yes' : 'No') . "\n";
if ($exists) {
// Element-Eigenschaften
$element = $browser->element($selector);
echo "Visible: " . ($element->isDisplayed() ? 'Yes' : 'No') . "\n";
echo "Enabled: " . ($element->isEnabled() ? 'Yes' : 'No') . "\n";
echo "Text: " . $element->getText() . "\n";
echo "HTML: " . $element->getDomProperty('outerHTML') . "\n";
}
echo "=== End Debug ===\n";
}
# Logging konfigurieren
// config/logging.php - Dusk Channel hinzufügen
'channels' => [
'dusk' => [
'driver' => 'daily',
'path' => storage_path('logs/dusk.log'),
'level' => 'debug',
],
],
// In Tests verwenden
Log::channel('dusk')->info('Test step completed', [
'url' => $browser->driver->getCurrentURL(),
'title' => $browser->driver->getTitle(),
]);
# Performance-Optimierung
# Browser-Konfiguration optimieren
// config/dusk.php
$options = (new ChromeOptions)->addArguments([
'--no-sandbox',
'--disable-dev-shm-usage',
'--disable-gpu',
'--disable-web-security',
'--disable-features=VizDisplayCompositor',
'--disable-extensions',
'--disable-plugins',
'--disable-images', // Für schnellere Tests
'--window-size=1920,1080',
]);
# Parallele Test-Ausführung
# Tests parallel ausführen
php artisan dusk --parallel
# Anzahl Prozesse definieren
php artisan dusk --parallel --processes=4
# Troubleshooting-Checkliste
Wenn deine Dusk-Tests fehlschlagen, arbeite diese Checkliste ab:
- [ ] Browser-Version kompatibel? ChromeDriver Version prüfen
- [ ] Selektoren korrekt? Dusk-Selektoren mit
@verwenden - [ ] Timing-Probleme?
waitFor()stattpause()verwenden - [ ] JavaScript-Errors? Browser-Console prüfen
- [ ] Authentifizierung? Login-Status validieren
- [ ] Datenbankzustand? Transaktionen oder Refresh prüfen
- [ ] Screenshots gemacht? Visueller Debugging-Check
- [ ] Headless-Modus? Temporär deaktivieren für Debugging
- [ ] Network-Requests? AJAX-Calls abwarten
- [ ] CSS-Animationen? Vollständig abgeschlossen?
# Nützliche Dusk-Methoden für Debugging
// Informationen sammeln
$browser->dump(); // HTML ausgeben
$browser->ddConsole(); // Console-Logs ausgeben
$browser->screenshot('debug'); // Screenshot machen
$browser->pause(); // Browser pausieren
// Element-Debugging
$browser->scrollTo('@element'); // Zu Element scrollen
$browser->mouseover('@element'); // Hover-Effekte testen
$browser->rightClick('@element'); // Rechtsklick-Menüs
// Status prüfen
$browser->assertSee('Expected text');
$browser->assertDontSee('Unexpected text');
$browser->assertPathIs('/expected/path');
$browser->assertRouteIs('route.name');
# Fazit
Das Debuggen von Laravel Dusk-Tests erfordert Geduld und systematisches Vorgehen. Die wichtigsten Prinzipien:
- Verwende explizite Waits statt fixer Pausen
- Sammle Debugging-Informationen (Screenshots, Logs, Console)
- Teste schrittweise mit kleineren, fokussierten Tests
- Nutze die richtigen Selektoren und Dusk-Attribute
- Verstehe das Timing deiner Anwendung
Mit diesen Strategien wirst du die meisten Dusk-Probleme erfolgreich lösen können.
# übergeordnetes Thema
2.7 Tests