Prologo
Primi Passi
Architettura
Le Basi
- Routing
- Middleware
- Protezione da CSRF
- Controller
- Richieste
- Risposte
- Views
- Blade
- Vite
- URL
- Sessioni
- Validazione
- Errori
- Logging
Approfondimenti
- Artisan
- Broadcasting
- Cache
- Collezioni
- Concorrenza
- Contesto
- Contratti
- Eventi
- File System
- Helpers
- Client HTTP
- Localizzazione
- Notifiche
- Sviluppo di Package
- Processi
- Code
- Rate-limiting
- Stringhe
- Scheduling di Task
Sicurezza
Database
Eloquent ORM
Testing
Package
Browser Testing
- Introduzione
- Installazione
- Iniziare
- Nozioni di base del browser
- Interagire con gli elementi
- Asserzioni Disponibili
- Pagine
- Componenti
- Integrazione Continua
Introduzione
Laravel Dusk offre un’API espressiva e facile da usare per l’automazione e il testing del browser. Di default, Dusk non richiede l’installazione di JDK o Selenium sul tuo computer locale. Invece, Dusk utilizza un’installazione autonoma di ChromeDriver. Tuttavia, puoi utilizzare qualsiasi altro driver compatibile con Selenium che preferisci.
Installazione
Per iniziare, dovresti installare Google Chrome e aggiungere la dipendenza Composer laravel/dusk
al tuo progetto:
composer require laravel/dusk --dev
Se stai registrando manualmente il service provider di Dusk, non dovresti mai registrarlo nell’ambiente di produzione, poiché ciò potrebbe permettere a utenti non autorizzati di autenticarsi con la tua applicazione.
Dopo aver installato il pacchetto Dusk, esegui il comando Artisan dusk:install
. Il comando dusk:install
creerà una cartella tests/Browser
, un test di esempio Dusk e installerà il binario di Chrome Driver per il tuo sistema operativo:
php artisan dusk:install
Successivamente, imposta la variabile d’ambiente APP_URL
nel file .env
della tua applicazione. Questo valore dovrebbe corrispondere all’URL che usi per accedere alla tua applicazione nel browser.
Se stai usando Laravel Sail per gestire il tuo ambiente di sviluppo locale, consulta anche la documentazione di Sail su come configurare ed eseguire i test Dusk.
Gestione delle installazioni di ChromeDriver
Se desideri installare una versione diversa di ChromeDriver rispetto a quella installata da Laravel Dusk tramite il comando dusk:install
, puoi usare il comando dusk:chrome-driver
:
# Installa l'ultima versione di ChromeDriver per il tuo sistema operativo...
php artisan dusk:chrome-driver
# Installa una versione specifica di ChromeDriver per il tuo OS...
php artisan dusk:chrome-driver 86
# Installa una versione specifica di ChromeDriver per tutti i sistemi operativi supportati...
php artisan dusk:chrome-driver --all
# Installa la versione di ChromeDriver che corrisponde alla versione rilevata di Chrome / Chromium per il tuo sistema operativo...
php artisan dusk:chrome-driver --detect
Dusk richiede che i binari
chromedriver
siano eseguibili. Se hai problemi nell’eseguire Dusk, assicurati che i binari siano eseguibili usando il seguente comando:chmod -R 0755 vendor/laravel/dusk/bin/
.
Utilizzo di Altri Browser
Per default, Dusk utilizza Google Chrome e un’installazione standalone di ChromeDriver per eseguire i test del browser. Tuttavia, puoi avviare il tuo server Selenium ed eseguire i test su qualsiasi browser desideri.
Per iniziare, apri il file tests/DuskTestCase.php
, che è il caso di test base di Dusk per la tua applicazione. All’interno di questo file, puoi rimuovere la chiamata al metodo startChromeDriver
. Questo impedirà a Dusk di avviare automaticamente ChromeDriver:
/**
* Prepara per l'esecuzione dei test Dusk.
*
* @beforeClass
*/
public static function prepare(): void
{
// static::startChromeDriver();
}
Successivamente, puoi modificare il metodo driver
per connetterti all’URL e alla porta di tua scelta. Inoltre, puoi modificare le "desired capabilities" che devono essere passate a WebDriver:
use Facebook\WebDriver\Remote\RemoteWebDriver;
/**
* Crea l'istanza di RemoteWebDriver.
*/
protected function driver(): RemoteWebDriver
{
return RemoteWebDriver::create(
'http://localhost:4444/wd/hub', DesiredCapabilities::phantomjs()
);
}
Iniziare
Generazione dei Test
Per creare un test Dusk, utilizza il comando Artisan dusk:make
. Il test generato sarà posizionato nella directory tests/Browser
:
php artisan dusk:make LoginTest
Resettare il Database Dopo Ogni Test
La maggior parte dei test che scrivi interagirà con pagine che recuperano dati dal database della tua applicazione; tuttavia, i tuoi test Dusk non dovrebbero mai usare il trait RefreshDatabase
. Il trait RefreshDatabase
sfrutta le transazioni del database che non saranno applicabili o disponibili tra richieste HTTP. Invece, hai due opzioni: il trait DatabaseMigrations
e il trait DatabaseTruncation
.
Utilizzo delle migrazioni del database
Il trait DatabaseMigrations
esegue le migrazioni del database prima di ogni test. Tuttavia, eliminare e ricreare le tabelle del database per ogni test è generalmente più lento rispetto a troncarle:
<?php
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
uses(DatabaseMigrations::class);
//
<?php
namespace Tests\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
class ExampleTest extends DuskTestCase
{
use DatabaseMigrations;
//
}
I database SQLite in-memory non possono essere utilizzati durante l’esecuzione dei test Dusk. Poiché il browser opera in un processo separato, non sarà in grado di accedere ai database in-memory di altri processi.
Utilizzo della Troncatura del Database
Il trait DatabaseTruncation
migrate il tuo database al primo test per assicurarsi che le tabelle del database siano state create correttamente. Tuttavia, nei test successivi, le tabelle del database verranno semplicemente troncate, offrendo un aumento di velocità rispetto al riavvio di tutte le migrazioni del database:
<?php
use Illuminate\Foundation\Testing\DatabaseTruncation;
use Laravel\Dusk\Browser;
uses(DatabaseTruncation::class);
//
<?php
namespace Tests\Browser;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTruncation;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
class ExampleTest extends DuskTestCase
{
use DatabaseTruncation;
//
}
Per impostazione predefinita, questo trait tronca tutte le tabelle tranne la tabella migrations
. Se desideri personalizzare le tabelle da troncare, puoi definire una proprietà $tablesToTruncate
nella tua classe di test:
Se stai usando Pest, dovresti definire proprietà o metodi nella classe base
DuskTestCase
o in qualsiasi classe che il tuo file di test estende.
/**
* Indica quali tabelle devono essere troncate.
*
* @var array
*/
protected $tablesToTruncate = ['users'];
In alternativa, puoi definire una proprietà $exceptTables
nella tua classe di test per specificare quali tabelle devono essere escluse dalla troncatura:
/**
* Indica quali tabelle devono essere escluse dalla troncatura.
*
* @var array
*/
protected $exceptTables = ['users'];
Per specificare le connessioni al database le cui tabelle devono essere troncate, puoi definire una proprietà $connectionsToTruncate
nella tua classe di test:
/**
* Indica quali connessioni devono avere le loro tabelle troncate.
*
* @var array
*/
protected $connectionsToTruncate = ['mysql'];
Se desideri eseguire del codice prima o dopo che la troncatura del database venga eseguita, puoi definire i metodi beforeTruncatingDatabase
o afterTruncatingDatabase
nella tua classe di test:
/**
* Esegue qualsiasi operazione che dovrebbe avvenire prima che il database inizi a troncare.
*/
protected function beforeTruncatingDatabase(): void
{
//
}
/**
* Esegue qualsiasi operazione che dovrebbe avvenire dopo che il database ha finito di troncare.
*/
protected function afterTruncatingDatabase(): void
{
//
}
Esecuzione dei Test
Per eseguire i test del browser, esegui il comando Artisan dusk
:
php artisan dusk
Se l’ultima volta che hai eseguito il comando dusk
hai avuto dei test falliti, puoi risparmiare tempo rieseguendo prima i test che non sono riusciti usando il comando dusk:fails
:
php artisan dusk:fails
Il comando dusk
accetta qualsiasi argomento normalmente accettato dal runner di test Pest / PHPUnit, permettendoti ad esempio di eseguire solo i test di un determinato gruppo:
php artisan dusk --group=foo
Se stai usando Laravel Sail per gestire il tuo ambiente di sviluppo locale, consulta la documentazione di Sail su configurare ed eseguire i test Dusk.
Avvio manuale di ChromeDriver
Per impostazione predefinita, Dusk tenterà automaticamente di avviare ChromeDriver. Se ciò non funziona sul tuo sistema, puoi avviare manualmente ChromeDriver prima di eseguire il comando dusk
. Se scegli di avviare manualmente ChromeDriver, dovresti commentare la seguente riga nel file tests/DuskTestCase.php
:
/**
* Prepara per l'esecuzione dei test Dusk.
*
* @beforeClass
*/
public static function prepare(): void
{
// static::startChromeDriver();
}
Inoltre, se avvii ChromeDriver su una porta diversa da 9515, dovresti modificare il metodo driver
della stessa classe per riflettere la porta corretta:
use Facebook\WebDriver\Remote\RemoteWebDriver;
/**
* Crea l'istanza di RemoteWebDriver.
*/
protected function driver(): RemoteWebDriver
{
return RemoteWebDriver::create(
'http://localhost:9515', DesiredCapabilities::chrome()
);
}
Gestione dell’Ambiente
Per fare in modo che Dusk utilizzi il proprio file di ambiente durante l’esecuzione dei test, crea un file .env.dusk.{environment}
nella root del tuo progetto. Ad esempio, se avvierai il comando dusk
dal tuo ambiente local
, dovresti creare un file .env.dusk.local
.
Durante l’esecuzione dei test, Dusk effettuerà una copia di backup del tuo file .env
e rinominerà l’ambiente Dusk in .env
. Una volta completati i test, il tuo file .env
sarà ripristinato.
Nozioni di base del browser
Creazione dei Browser
Per iniziare, scriviamo un test che verifica se possiamo effettuare il login nella nostra applicazione. Dopo aver generato un test, possiamo modificarlo per navigare alla pagina di login, inserire alcune credenziali e cliccare il pulsante "Login". Per creare un’istanza del browser, puoi chiamare il metodo browse
all’interno del tuo test Dusk:
<?php
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
uses(DatabaseMigrations::class);
test('basic example', function () {
$user = User::factory()->create([
'email' => 'taylor@laravel.com',
]);
$this->browse(function (Browser $browser) use ($user) {
$browser->visit('/login')
->type('email', $user->email)
->type('password', 'password')
->press('Login')
->assertPathIs('/home');
});
});
<?php
namespace Tests\Browser;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
class ExampleTest extends DuskTestCase
{
use DatabaseMigrations;
/**
* Un esempio base di test browser.
*/
public function test_basic_example(): void
{
$user = User::factory()->create([
'email' => 'taylor@laravel.com',
]);
$this->browse(function (Browser $browser) use ($user) {
$browser->visit('/login')
->type('email', $user->email)
->type('password', 'password')
->press('Login')
->assertPathIs('/home');
});
}
}
Come puoi vedere nell’esempio sopra, il metodo browse
accetta una closure. Un’istanza del browser verrà passata automaticamente a questa closure da Dusk ed è l’oggetto principale usato per interagire e fare asserzioni sulla tua applicazione.
Creare Più Browser
A volte potresti aver bisogno di più browser per eseguire correttamente un test. Ad esempio, potrebbero servire più browser per testare una schermata di chat che interagisce con i websockets. Per creare più browser, aggiungi semplicemente più argomenti browser alla firma della closure passata al metodo browse
:
$this->browse(function (Browser $first, Browser $second) {
$first->loginAs(User::find(1))
->visit('/home')
->waitForText('Message');
$second->loginAs(User::find(2))
->visit('/home')
->waitForText('Message')
->type('message', 'Hey Taylor')
->press('Send');
$first->waitForText('Hey Taylor')
->assertSee('Jeffrey Way');
});
Navigazione
Il metodo visit
può essere usato per navigare verso un determinato URI all’interno della tua applicazione:
$browser->visit('/login');
Puoi usare il metodo visitRoute
per navigare verso una route nominata:
$browser->visitRoute($routeName, $parameters);
Puoi navigare "indietro" e "avanti" usando i metodi back
e forward
:
$browser->back();
$browser->forward();
Puoi usare il metodo refresh
per ricaricare la pagina:
$browser->refresh();
Ridimensionamento delle Finestre del Browser
Puoi usare il metodo resize
per regolare la dimensione della finestra del browser:
$browser->resize(1920, 1080);
Il metodo maximize
può essere utilizzato per massimizzare la finestra del browser:
$browser->maximize();
Il metodo fitContent
ridimensiona la finestra del browser in base alle dimensioni del suo contenuto:
$browser->fitContent();
Quando un test fallisce, Dusk ridimensiona automaticamente il browser per adattarsi al contenuto prima di scattare uno screenshot. Puoi disabilitare questa funzione chiamando il metodo disableFitOnFailure
all’interno del tuo test:
$browser->disableFitOnFailure();
Puoi usare il metodo move
per spostare la finestra del browser in una posizione diversa sullo schermo:
$browser->move($x = 100, $y = 100);
Macro del Browser
Se desideri definire un metodo personalizzato del browser che puoi riutilizzare in diversi test, puoi usare il metodo macro
sulla classe Browser
. Tipicamente, dovresti chiamare questo metodo dal metodo boot
di un provider di servizi:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Laravel\Dusk\Browser;
class DuskServiceProvider extends ServiceProvider
{
/**
* Registra le macro del browser di Dusk.
*/
public function boot(): void
{
Browser::macro('scrollToElement', function (string $element = null) {
$this->script("$('html, body').animate({ scrollTop: $('$element').offset().top }, 0);");
return $this;
});
}
}
La funzione macro
accetta un nome come primo argomento e una closure come secondo. La closure della macro verrà eseguita quando chiami la macro come metodo su un’istanza di Browser
:
$this->browse(function (Browser $browser) use ($user) {
$browser->visit('/pay')
->scrollToElement('#credit-card-details')
->assertSee('Enter Credit Card Details');
});
Autenticazione
Spesso testerai pagine che richiedono autenticazione. Puoi usare il metodo loginAs
di Dusk per evitare di interagire con la schermata di login della tua applicazione in ogni test. Il metodo loginAs
accetta una chiave primaria associata al tuo modello autenticabile o un’istanza del modello autenticabile:
use App\Models\User;
use Laravel\Dusk\Browser;
$this->browse(function (Browser $browser) {
$browser->loginAs(User::find(1))
->visit('/home');
});
Dopo aver usato il metodo
loginAs
, la sessione dell’utente sarà mantenuta per tutti i test nel file.
Cookies
Puoi usare il metodo cookie
per ottenere o impostare il valore di un cookie crittografato. Per impostazione predefinita, tutti i cookie creati da Laravel sono crittografati:
$browser->cookie('name');
$browser->cookie('name', 'Taylor');
Puoi usare il metodo plainCookie
per ottenere o impostare il valore di un cookie non crittografato:
$browser->plainCookie('name');
$browser->plainCookie('name', 'Taylor');
Puoi usare il metodo `deleteCookie` per eliminare il cookie specificato:
$browser->deleteCookie('name');
Eseguire JavaScript
Puoi utilizzare il metodo script
per eseguire istruzioni JavaScript arbitrarie nel browser:
$browser->script('document.documentElement.scrollTop = 0');
$browser->script([
'document.body.scrollTop = 0',
'document.documentElement.scrollTop = 0',
]);
$output = $browser->script('return window.location.pathname');
Fare uno Screenshot
Puoi utilizzare il metodo screenshot
per scattare uno screenshot e salvarlo con il nome file specificato. Tutti gli screenshot saranno salvati nella directory tests/Browser/screenshots
:
$browser->screenshot('filename');
Il metodo responsiveScreenshots
può essere usato per scattare una serie di screenshot a vari breakpoint:
$browser->responsiveScreenshots('filename');
Il metodo screenshotElement
può essere utilizzato per scattare uno screenshot di un elemento specifico sulla pagina:
$browser->screenshotElement('#selector', 'filename');
Salvataggio dell’output della Console su Disco
Puoi usare il metodo storeConsoleLog
per scrivere l’output della console del browser corrente su disco con il nome di file specificato. L’output della console sarà salvato nella directory tests/Browser/console
:
$browser->storeConsoleLog('filename');
Salvare il Sorgente della Pagina su Disco
Puoi usare il metodo storeSource
per scrivere il sorgente della pagina corrente su disco con il nome del file specificato. Il sorgente sarà salvato nella directory tests/Browser/source
:
$browser->storeSource('filename');
Interagire con gli elementi
Dusk Selectors
Scegliere selettori CSS efficaci per interagire con gli elementi è una delle parti più difficili della scrittura dei test Dusk. Nel tempo, i cambiamenti nel frontend possono far sì che selettori CSS come il seguente rompano i tuoi test:
// HTML...
<button>Login</button>
// Test...
$browser->click('.login-page .container div > button');
I selettori Dusk ti permettono di concentrarti sulla scrittura di test efficaci invece di ricordare i selettori CSS. Per definire un selettore, aggiungi un attributo dusk
al tuo elemento HTML. Poi, quando interagisci con un browser Dusk, prefissa il selettore con @
per manipolare l’elemento associato nel tuo test:
// HTML...
<button dusk="login-button">Login</button>
// Test...
$browser->click('@login-button');
Se desideri, puoi personalizzare l’attributo HTML che il selettore Dusk utilizza tramite il metodo selectorHtmlAttribute
. Tipicamente, questo metodo dovrebbe essere chiamato dal metodo boot
del AppServiceProvider
della tua applicazione:
use Laravel\Dusk\Dusk;
Dusk::selectorHtmlAttribute('data-dusk');
Testo, Valori e Attributi
Recuperare e Impostare Valori
Dusk offre vari metodi per interagire con il valore attuale, il testo visualizzato e gli attributi degli elementi sulla pagina. Ad esempio, per ottenere il "value" di un elemento che corrisponde a un selettore CSS o Dusk, usa il metodo value
:
// Recupera il valore...
$value = $browser->value('selector');
// Imposta il valore...
$browser->value('selector', 'value');
Puoi usare il metodo inputValue
per ottenere il "value" di un elemento di input con un nome di campo specifico:
$value = $browser->inputValue('field');
Recuperare Testo
Il metodo text
può essere utilizzato per ottenere il testo visualizzato di un elemento che corrisponde al selettore specificato:
$text = $browser->text('selector');
Recupero degli Attributi
Infine, il metodo attribute
può essere utilizzato per ottenere il valore di un attributo di un elemento che corrisponde al selettore fornito:
$attribute = $browser->attribute('selector', 'value');
Interagire con i Forms
Inserimento di Valori
Dusk offre diversi metodi per interagire con i moduli e gli elementi di input. Prima di tutto, vediamo un esempio di inserimento di testo in un campo di input:
$browser->type('email', 'taylor@laravel.com');
Nota che, anche se il metodo accetta un selettore CSS se necessario, non è obbligatorio passarlo al metodo type
. Se non viene fornito un selettore CSS, Dusk cercherà un campo input
o textarea
con l’attributo name
specificato.
Per aggiungere testo a un campo senza cancellarne il contenuto, puoi usare il metodo append
:
$browser->type('tags', 'foo')
->append('tags', ', bar, baz');
Puoi cancellare il valore di un input usando il metodo clear
:
$browser->clear('email');
Puoi far digitare lentamente a Dusk utilizzando il metodo typeSlowly
. Di default, Dusk farà una pausa di 100 millisecondi tra ogni pressione di tasto. Per personalizzare il tempo tra le pressioni di tasto, puoi passare il numero di millisecondi desiderato come terzo argomento del metodo:
$browser->typeSlowly('mobile', '+1 (202) 555-5555');
$browser->typeSlowly('mobile', '+1 (202) 555-5555', 300);
Puoi utilizzare il metodo appendSlowly
per aggiungere testo lentamente:
$browser->type('tags', 'foo')
->appendSlowly('tags', ', bar, baz');
Menu a discesa
Per selezionare un valore disponibile in un elemento select
, puoi utilizzare il metodo select
. Come il metodo type
, il metodo select
non richiede un selettore CSS completo. Quando passi un valore al metodo select
, dovresti passare il valore dell’opzione sottostante invece del testo visualizzato:
$browser->select('size', 'Large');
Puoi selezionare un’opzione casuale omettendo il secondo argomento:
$browser->select('size');
Fornendo un array come secondo argomento al metodo select
, puoi istruire il metodo a selezionare più opzioni:
$browser->select('categories', ['Art', 'Music']);
Checkbox
Per selezionare una checkbox, puoi usare il metodo check
. Come molti altri metodi per gli input, non è necessario un selettore CSS completo. Se non viene trovato un selettore CSS corrispondente, Dusk cercherà una checkbox con l’attributo name
uguale:
$browser->check('terms');
Per deselezionare una checkbox, usa il metodo uncheck
:
$browser->uncheck('terms');
Radio Buttons
Per "selezionare" un’opzione di input radio
, puoi usare il metodo radio
. Come molti altri metodi legati agli input, non è necessario un selettore CSS completo. Se non viene trovata una corrispondenza con un selettore CSS, Dusk cercherà un input radio
con attributi name
e value
corrispondenti:
$browser->radio('size', 'large');
Allegare File
Il metodo attach
serve ad allegare un file a un elemento di input file
. Come molti altri metodi per gli input, non è necessario un selettore CSS completo. Se non si trova una corrispondenza con il selettore CSS, Dusk cercherà un input file
con l’attributo name
corrispondente:
$browser->attach('photo', __DIR__.'/photos/mountains.png');
La funzione attach richiede che l’estensione PHP
Zip
sia installata e abilitata sul server.
Premere Pulsanti
Il metodo press
può essere utilizzato per cliccare un elemento pulsante sulla pagina. L’argomento passato al metodo press
può essere sia il testo visibile del pulsante sia un selettore CSS / Dusk:
$browser->press('Login');
Quando si inviano i form, molte applicazioni disabilitano il pulsante di invio dopo che è stato premuto e poi lo riabilitano una volta completata la richiesta HTTP della sottomissione del form. Per premere un pulsante e aspettare che venga riabilitato, puoi utilizzare il metodo pressAndWaitFor
:
// Premi il pulsante e aspetta al massimo 5 secondi che sia abilitato...
$browser->pressAndWaitFor('Save');
// Premi il pulsante e aspetta al massimo 1 secondo che sia abilitato...
$browser->pressAndWaitFor('Save', 1);
Clic sui link
Per cliccare un link, puoi usare il metodo clickLink
sull’istanza del browser. Il metodo clickLink
cliccherà il link che ha il testo visualizzato specificato:
$browser->clickLink($linkText);
Puoi usare il metodo seeLink
per verificare se un link con il testo visualizzato specificato è visibile sulla pagina:
if ($browser->seeLink($linkText)) {
// ...
}
Questi metodi interagiscono con jQuery. Se jQuery non è disponibile sulla pagina, Dusk lo inietterà automaticamente nella pagina in modo che sia disponibile per la durata del test.
Utilizzo della Tastiera
Il metodo keys
permette di fornire sequenze di input più complesse a un elemento rispetto a quanto normalmente consentito dal metodo type
. Ad esempio, puoi istruirlo a tenere premuti i tasti modificatori mentre inserisci dei valori. In questo esempio, il tasto shift
sarà premuto mentre viene inserito taylor
nell’elemento corrispondente al selettore specificato. Dopo aver digitato taylor
, verrà digitato swift
senza nessun tasto modificatore:
$browser->keys('selector', ['{shift}', 'taylor'], 'swift');
Un altro utilizzo utile del metodo keys
è inviare una combinazione di "scorciatoia da tastiera" al selettore CSS principale della tua applicazione:
$browser->keys('.app', ['{command}', 'j']);
Tutti i tasti modificatori come
{command}
sono racchiusi tra parentesi graffe{}
, e corrispondono alle costanti definite nella classeFacebook\WebDriver\WebDriverKeys
, che possono essere trovate su GitHub.
Interazioni fluide con la tastiera
Dusk offre anche un metodo withKeyboard
, che permette di eseguire interazioni complesse con la tastiera in modo fluido tramite la classe Laravel\Dusk\Keyboard
. La classe Keyboard
fornisce i metodi press
, release
, type
e pause
:
use Laravel\Dusk\Keyboard;
$browser->withKeyboard(function (Keyboard $keyboard) {
$keyboard->press('c')
->pause(1000)
->release('c')
->type(['c', 'e', 'o']);
});
Macro da Tastiera
Se desideri definire interazioni da tastiera personalizzate che puoi facilmente riutilizzare in tutta la tua suite di test, puoi utilizzare il metodo macro
fornito dalla classe Keyboard
. Di solito, dovresti chiamare questo metodo dal metodo boot
di un provider di servizi boot
:
<?php
namespace App\Providers;
use Facebook\WebDriver\WebDriverKeys;
use Illuminate\Support\ServiceProvider;
use Laravel\Dusk\Keyboard;
use Laravel\Dusk\OperatingSystem;
class DuskServiceProvider extends ServiceProvider
{
/**
* Registra le macro del browser di Dusk.
*/
public function boot(): void
{
Keyboard::macro('copy', function (string $element = null) {
$this->type([
OperatingSystem::onMac() ? WebDriverKeys::META : WebDriverKeys::CONTROL, 'c',
]);
return $this;
});
Keyboard::macro('paste', function (string $element = null) {
$this->type([
OperatingSystem::onMac() ? WebDriverKeys::META : WebDriverKeys::CONTROL, 'v',
]);
return $this;
});
}
}
La funzione macro
accetta un nome come primo argomento e una closure come secondo argomento. La closure della macro verrà eseguita quando si chiama la macro come metodo su un’istanza di Keyboard
:
$browser->click('@textarea')
->withKeyboard(fn (Keyboard $keyboard) => $keyboard->copy())
->click('@another-textarea')
->withKeyboard(fn (Keyboard $keyboard) => $keyboard->paste());
Usare il Mouse
Cliccare sugli Elementi
Il metodo click
può essere usato per cliccare su un elemento che corrisponde al selettore CSS o Dusk fornito:
$browser->click('.selector');
Il metodo clickAtXPath
può essere usato per cliccare su un elemento che corrisponde all’espressione XPath fornita:
$browser->clickAtXPath('//div[@class = "selector"]');
Il metodo clickAtPoint
può essere usato per cliccare sull’elemento più in alto in un dato paio di coordinate relative all’area visibile del browser:
$browser->clickAtPoint($x = 0, $y = 0);
Il metodo doubleClick
può essere usato per simulare un doppio clic del mouse:
$browser->doubleClick();
$browser->doubleClick('.selector');
Il metodo rightClick
può essere usato per simulare un clic destro del mouse:
$browser->rightClick();
$browser->rightClick('.selector');
Il metodo clickAndHold
può essere usato per simulare la pressione e il mantenimento di un pulsante del mouse. Una chiamata successiva al metodo releaseMouse
annullerà questo comportamento e rilascerà il pulsante del mouse:
$browser->clickAndHold('.selector');
$browser->clickAndHold()
->pause(1000)
->releaseMouse();
Il metodo controlClick
può essere usato per simulare l’evento ctrl+click
all’interno del browser:
$browser->controlClick();
$browser->controlClick('.selector');
Mouseover
Il metodo mouseover
può essere usato quando devi spostare il mouse su un elemento che corrisponde al selettore CSS o Dusk fornito:
$browser->mouseover('.selector');
Trascinamento e Rilascio
Il metodo drag
può essere usato per trascinare un elemento che corrisponde al selettore dato verso un altro elemento:
$browser->drag('.from-selector', '.to-selector');
Oppure, puoi trascinare un elemento in una sola direzione:
$browser->dragLeft('.selector', $pixels = 10);
$browser->dragRight('.selector', $pixels = 10);
$browser->dragUp('.selector', $pixels = 10);
$browser->dragDown('.selector', $pixels = 10);
Infine, puoi trascinare un elemento di uno spostamento specifico:
$browser->dragOffset('.selector', $x = 10, $y = 10);
Dialoghi JavaScript
Dusk offre diversi metodi per interagire con i dialoghi JavaScript. Ad esempio, puoi usare il metodo waitForDialog
per aspettare che appaia un dialogo JavaScript. Questo metodo accetta un argomento opzionale che specifica quanti secondi aspettare prima che il dialogo appaia:
$browser->waitForDialog($seconds = null);
Il metodo assertDialogOpened
può essere utilizzato per verificare che un dialogo sia stato mostrato e contenga il messaggio specificato:
$browser->assertDialogOpened('Dialog message');
Se il dialogo JavaScript include un prompt, puoi usare il metodo typeInDialog
per inserire un valore nel prompt:
$browser->typeInDialog('Hello World');
Per chiudere un dialogo JavaScript aperto cliccando il pulsante "OK", puoi utilizzare il metodo acceptDialog
:
$browser->acceptDialog();
Per chiudere un dialogo JavaScript aperto cliccando il pulsante "Cancel", puoi utilizzare il metodo dismissDialog
:
$browser->dismissDialog();
Interagire con gli iframe
Se hai bisogno di interagire con elementi all’interno di un iframe, puoi usare il metodo withinFrame
. Tutte le interazioni con gli elementi che avvengono all’interno della closure fornita al metodo withinFrame
saranno limitate al contesto dell’iframe specificato:
$browser->withinFrame('#credit-card-details', function ($browser) {
$browser->type('input[name="cardnumber"]', '4242424242424242')
->type('input[name="exp-date"]', '1224')
->type('input[name="cvc"]', '123')
->press('Pay');
});
Ambito dei Selettori
A volte potresti voler eseguire diverse operazioni limitandole tutte a un determinato selettore. Per esempio, potresti voler verificare che un certo testo esista solo all’interno di una tabella e poi cliccare un pulsante all’interno di quella tabella. Puoi usare il metodo with
per fare questo. Tutte le operazioni eseguite all’interno della closure passata al metodo with
saranno limitate al selettore originale:
$browser->with('.table', function (Browser $table) {
$table->assertSee('Hello World')
->clickLink('Delete');
});
Occasionalmente potresti aver bisogno di eseguire verifiche al di fuori dell’ambito attuale. Puoi usare i metodi elsewhere
ed elsewhereWhenAvailable
per fare questo:
$browser->with('.table', function (Browser $table) {
// L'ambito attuale è `body .table`...
$browser->elsewhere('.page-title', function (Browser $title) {
// L'ambito attuale è `body .page-title`...
$title->assertSee('Hello World');
});
$browser->elsewhereWhenAvailable('.page-title', function (Browser $title) {
// L'ambito attuale è `body .page-title`...
$title->assertSee('Hello World');
});
});
Attendere gli Elementi
Quando si testano applicazioni che utilizzano ampiamente JavaScript, spesso è necessario "attendere" che certi elementi o dati siano disponibili prima di procedere con un test. Dusk rende questo semplice. Utilizzando vari metodi, puoi aspettare che gli elementi diventino visibili sulla pagina o anche aspettare che un’espressione JavaScript restituisca true
.
Attesa
Se devi semplicemente mettere in pausa il test per un determinato numero di millisecondi, usa il metodo pause
:
$browser->pause(1000);
Se hai bisogno di mettere in pausa il test solo se una certa condizione è true
, usa il metodo pauseIf
:
$browser->pauseIf(App::environment('production'), 1000);
Allo stesso modo, se devi mettere in pausa il test a meno che una condizione non sia true
, puoi usare il metodo pauseUnless
:
$browser->pauseUnless(App::environment('testing'), 1000);
Attendere i selettori
Il metodo waitFor
può essere utilizzato per mettere in pausa l’esecuzione del test fino a quando l’elemento che corrisponde al selettore CSS o Dusk fornito non viene visualizzato nella pagina. Per impostazione predefinita, questa pausa durerà al massimo cinque secondi prima di generare un’eccezione. Se necessario, puoi passare un limite di timeout personalizzato come secondo argomento del metodo:
// Attendere al massimo cinque secondi per il selettore...
$browser->waitFor('.selector');
// Attendere al massimo un secondo per il selettore...
$browser->waitFor('.selector', 1);
Puoi anche attendere fino a quando l’elemento che corrisponde al selettore specificato contiene il testo dato:
// Attendere al massimo cinque secondi affinché il selettore contenga il testo specificato...
$browser->waitForTextIn('.selector', 'Hello World');
// Attendere al massimo un secondo affinché il selettore contenga il testo specificato...
$browser->waitForTextIn('.selector', 'Hello World', 1);
Puoi inoltre attendere fino a quando l’elemento che corrisponde al selettore specificato non è più presente nella pagina:
// Attendere al massimo cinque secondi fino a quando il selettore non è presente...
$browser->waitUntilMissing('.selector');
// Attendere al massimo un secondo fino a quando il selettore non è presente...
$browser->waitUntilMissing('.selector', 1);
Oppure, puoi attendere fino a quando l’elemento che corrisponde al selettore specificato è abilitato o disabilitato:
// Attendere al massimo cinque secondi fino a quando il selettore è abilitato...
$browser->waitUntilEnabled('.selector');
// Attendere al massimo un secondo fino a quando il selettore è abilitato...
$browser->waitUntilEnabled('.selector', 1);
// Attendere al massimo cinque secondi fino a quando il selettore è disabilitato...
$browser->waitUntilDisabled('.selector');
// Attendere al massimo un secondo fino a quando il selettore è disabilitato...
$browser->waitUntilDisabled('.selector', 1);
Limitare i Selettori Quando Disponibili
A volte, potresti voler aspettare che un elemento appaia che corrisponde a un determinato selettore e poi interagire con esso. Ad esempio, potresti voler attendere che una finestra modale sia disponibile e poi premere il pulsante "OK" all’interno della modale. Il metodo whenAvailable
può essere utilizzato per questo scopo. Tutte le operazioni sugli elementi eseguite all’interno della closure saranno limitate al selettore originale:
$browser->whenAvailable('.modal', function (Browser $modal) {
$modal->assertSee('Hello World')
->press('OK');
});
Attendere il Testo
Il metodo waitForText
può essere utilizzato per attendere che il testo specificato venga visualizzato sulla pagina:
// Attendi al massimo cinque secondi per il testo...
$browser->waitForText('Hello World');
// Attendi al massimo un secondo per il testo...
$browser->waitForText('Hello World', 1);
Puoi utilizzare il metodo waitUntilMissingText
per attendere che il testo visualizzato venga rimosso dalla pagina:
// Attendi al massimo cinque secondi per la rimozione del testo...
$browser->waitUntilMissingText('Hello World');
// Attendi al massimo un secondo per la rimozione del testo...
$browser->waitUntilMissingText('Hello World', 1);
Attendere i Link
Il metodo waitForLink
può essere usato per attendere che il testo del link specificato sia visualizzato sulla pagina:
// Attendere al massimo cinque secondi per il link...
$browser->waitForLink('Create');
// Attendere al massimo un secondo per il link...
$browser->waitForLink('Create', 1);
Attesa degli input
Il metodo waitForInput
può essere utilizzato per attendere che il campo di input specificato sia visibile nella pagina:
// Attendi al massimo cinque secondi per l'input...
$browser->waitForInput($field);
// Attendi al massimo un secondo per l'input...
$browser->waitForInput($field, 1);
Attendere la Posizione della Pagina
Quando si effettua un’asserzione sul percorso come $browser->assertPathIs('/home')
, l’asserzione può fallire se window.location.pathname
viene aggiornato in modo asincrono. Puoi usare il metodo waitForLocation
per attendere che la posizione sia un valore specifico:
$browser->waitForLocation('/secret');
Il metodo waitForLocation
può essere usato anche per attendere che la posizione attuale della finestra sia un URL completo:
$browser->waitForLocation('https://example.com/path');
Puoi anche attendere la posizione di una route nominata:
$browser->waitForRoute($routeName, $parameters);
Attendere il Ricaricamento della Pagina
Se devi attendere che una pagina si ricarichi dopo aver eseguito un’azione, usa il metodo waitForReload
:
use Laravel\Dusk\Browser;
$browser->waitForReload(function (Browser $browser) {
$browser->press('Submit');
})
->assertSee('Success!');
Poiché spesso è necessario attendere il ricaricamento della pagina dopo aver cliccato un pulsante, puoi usare il metodo clickAndWaitForReload
per comodità:
$browser->clickAndWaitForReload('.selector')
->assertSee('something');
Attendere espressioni JavaScript
A volte potresti voler mettere in pausa l’esecuzione di un test finché una determinata espressione JavaScript non restituisce true
. Puoi facilmente farlo usando il metodo waitUntil
. Quando passi un’espressione a questo metodo, non è necessario includere la parola chiave return
o il punto e virgola finale:
// Attendi al massimo cinque secondi affinché l'espressione sia vera...
$browser->waitUntil('App.data.servers.length > 0');
// Attendi al massimo un secondo affinché l'espressione sia vera...
$browser->waitUntil('App.data.servers.length > 0', 1);
In attesa delle espressioni Vue
I metodi waitUntilVue
e waitUntilVueIsNot
possono essere usati per attendere che un attributo di un componente Vue abbia un determinato valore:
// Attendi finché l'attributo del componente contiene il valore specificato...
$browser->waitUntilVue('user.name', 'Taylor', '@user');
// Attendi finché l'attributo del componente non contiene il valore specificato...
$browser->waitUntilVueIsNot('user.name', null, '@user');
Attendere gli Eventi JavaScript
Il metodo waitForEvent
può essere utilizzato per mettere in pausa l’esecuzione di un test fino a quando si verifica un evento JavaScript:
$browser->waitForEvent('load');
Il listener dell’evento viene collegato all’ambito corrente, che per impostazione predefinita è l’elemento body
. Quando si utilizza un selettore con ambito, il listener dell’evento sarà collegato all’elemento corrispondente:
$browser->with('iframe', function (Browser $iframe) {
// Attendere l'evento load dell'iframe...
$iframe->waitForEvent('load');
});
Puoi anche fornire un selettore come secondo argomento del metodo waitForEvent
per collegare il listener dell’evento a un elemento specifico:
$browser->waitForEvent('load', '.selector');
Puoi anche attendere eventi sugli oggetti document
e window
:
// Attendere che il documento venga scrollato...
$browser->waitForEvent('scroll', 'document');
// Attendere al massimo cinque secondi fino a quando la finestra viene ridimensionata...
$browser->waitForEvent('resize', 'window', 5);
Attendere con una Callback
Molti dei metodi "wait" in Dusk si basano sul metodo waitUsing
. Puoi usare direttamente questo metodo per attendere che una determinata closure ritorni true
. Il metodo waitUsing
accetta il numero massimo di secondi da attendere, l’intervallo con cui valutare la closure, la closure stessa e un messaggio di errore opzionale:
$browser->waitUsing(10, 1, function () use ($something) {
return $something->isReady();
}, "Qualcosa non era pronto in tempo.");
Scorrere un elemento nella visualizzazione
A volte potresti non riuscire a cliccare su un elemento perché si trova al di fuori dell’area visibile del browser. Il metodo scrollIntoView
scorrerà la finestra del browser finché l’elemento con il selettore specificato non sarà visibile:
$browser->scrollIntoView('.selector')
->click('.selector');
Asserzioni Disponibili
Dusk offre una varietà di asserzioni che puoi utilizzare nella tua applicazione. Tutte le asserzioni disponibili sono documentate nell’elenco sottostante:
- assertTitle
- assertTitleContains
- assertUrlIs
- assertSchemeIs
- assertSchemeIsNot
- assertHostIs
- assertHostIsNot
- assertPortIs
- assertPortIsNot
- assertPathBeginsWith
- assertPathEndsWith
- assertPathContains
- assertPathIs
- assertPathIsNot
- assertRouteIs
- assertQueryStringHas
- assertQueryStringMissing
- assertFragmentIs
- assertFragmentBeginsWith
- assertFragmentIsNot
- assertHasCookie
- assertHasPlainCookie
- assertCookieMissing
- assertPlainCookieMissing
- assertCookieValue
- assertPlainCookieValue
- assertSee
- assertDontSee
- assertSeeIn
- assertDontSeeIn
- assertSeeAnythingIn
- assertSeeNothingIn
- assertScript
- assertSourceHas
- assertSourceMissing
- assertSeeLink
- assertDontSeeLink
- assertInputValue
- assertInputValueIsNot
- assertChecked
- assertNotChecked
- assertIndeterminate
- assertRadioSelected
- assertRadioNotSelected
- assertSelected
- assertNotSelected
- assertSelectHasOptions
- assertSelectMissingOptions
- assertSelectHasOption
- assertSelectMissingOption
- assertValue
- assertValueIsNot
- assertAttribute
- assertAttributeContains
- assertAttributeDoesntContain
- assertAriaAttribute
- assertDataAttribute
- assertVisible
- assertPresent
- assertNotPresent
- assertMissing
- assertInputPresent
- assertInputMissing
- assertDialogOpened
- assertEnabled
- assertDisabled
- assertButtonEnabled
- assertButtonDisabled
- assertFocused
- assertNotFocused
- assertAuthenticated
- assertGuest
- assertAuthenticatedAs
- assertVue
- assertVueIsNot
- assertVueContains
- assertVueDoesntContain
assertTitle
Verifica che il titolo della pagina corrisponda al testo fornito:
$browser->assertTitle($title);
assertTitleContains
Verifica che il titolo della pagina contenga il testo specificato:
$browser->assertTitleContains($title);
assertUrlIs
Verifica che l’URL corrente (senza la stringa di query) corrisponda alla stringa fornita:
$browser->assertUrlIs($url);
assertSchemeIs
Verifica che lo schema dell’URL attuale corrisponda allo schema specificato:
$browser->assertSchemeIs($scheme);
assertSchemeIsNot
Verifica che lo schema dell’URL attuale non corrisponda a quello fornito:
$browser->assertSchemeIsNot($scheme);
assertHostIs
Verifica che l’host dell’URL corrente corrisponda a quello fornito:
$browser->assertHostIs($host);
assertHostIsNot
Verifica che l’host dell’URL corrente non corrisponda all’host fornito:
$browser->assertHostIsNot($host);
assertPortIs
Verifica che la porta dell’URL corrente corrisponda alla porta specificata:
$browser->assertPortIs($port);
assertPortIsNot
Verifica che la porta dell’URL corrente non corrisponda alla porta specificata:
$browser->assertPortIsNot($port);
assertPathBeginsWith
Verifica che il percorso dell’URL corrente inizi con il percorso fornito:
$browser->assertPathBeginsWith('/home');
assertPathEndsWith
Verifica che il percorso URL attuale finisca con il percorso specificato:
$browser->assertPathEndsWith('/home');
assertPathContains
Verifica che il percorso dell’URL attuale contenga il percorso specificato:
$browser->assertPathContains('/home');
assertPathIs
Verifica che il percorso corrente corrisponda al percorso specificato:
$browser->assertPathIs('/home');
assertPathIsNot
Verifica che il percorso corrente non corrisponda al percorso fornito:
$browser->assertPathIsNot('/home');
assertRouteIs
Verifica che l’URL attuale corrisponda all’URL della route nominata:
$browser->assertRouteIs($name, $parameters);
assertQueryStringHas
Verifica che il parametro della query string specificato sia presente:
$browser->assertQueryStringHas($name);
Verifica che il parametro della query string specificato sia presente e abbia un valore dato:
$browser->assertQueryStringHas($name, $value);
assertQueryStringMissing
Verifica che il parametro della query string specificato sia assente:
$browser->assertQueryStringMissing($name);
assertFragmentIs
Verifica che l’attuale frammento hash dell’URL corrisponda al frammento fornito:
$browser->assertFragmentIs('anchor');
assertFragmentBeginsWith
Verifica che l’attuale frammento hash dell’URL inizi con il frammento fornito:
$browser->assertFragmentBeginsWith('anchor');
assertFragmentIsNot
Verifica che l’hash corrente dell’URL non corrisponda al frammento specificato:
$browser->assertFragmentIsNot('anchor');
assertHasCookie
Verifica che il cookie criptato specificato sia presente:
$browser->assertHasCookie($name);
assertHasPlainCookie
Verifica che il cookie non criptato fornito sia presente:
$browser->assertHasPlainCookie($name);
assertCookieMissing
Verifica che il cookie crittografato specificato non sia presente:
$browser->assertCookieMissing($name);
assertPlainCookieMissing
Verifica che il cookie non criptato specificato non sia presente:
$browser->assertPlainCookieMissing($name);
assertCookieValue
Verifica che un cookie crittografato abbia un determinato valore:
$browser->assertCookieValue($name, $value);
assertPlainCookieValue
Verifica che un cookie non crittografato abbia un determinato valore:
$browser->assertPlainCookieValue($name, $value);
assertSee
Verifica che il testo specificato sia presente nella pagina:
$browser->assertSee($text);
assertDontSee
Verifica che il testo fornito non sia presente sulla pagina:
$browser->assertDontSee($text);
assertSeeIn
Verifica che il testo fornito sia presente all’interno del selettore:
$browser->assertSeeIn($selector, $text);
assertDontSeeIn
Assicura che il testo fornito non sia presente all’interno del selettore:
$browser->assertDontSeeIn($selector, $text);
#### assertSeeAnythingIn
Verifica che qualsiasi testo sia presente all'interno del selettore:
$browser->assertSeeAnythingIn($selector);
assertSeeNothingIn
Verifica che nessun testo sia presente all’interno del selettore:
$browser->assertSeeNothingIn($selector);
assertScript
Verifica che un’espressione JavaScript restituisca il valore atteso:
$browser->assertScript('window.isLoaded')
->assertScript('document.readyState', 'complete');
assertSourceHas
Verifica che il codice sorgente fornito sia presente nella pagina:
$browser->assertSourceHas($code);
assertSourceMissing
Verifica che il codice sorgente specificato non sia presente sulla pagina:
$browser->assertSourceMissing($code);
assertSeeLink
Verifica che il link specificato sia presente nella pagina:
$browser->assertSeeLink($linkText);
assertDontSeeLink
Verifica che il link specificato non sia presente nella pagina:
$browser->assertDontSeeLink($linkText);
assertInputValue
Verifica che il campo di input specificato abbia il valore indicato:
$browser->assertInputValue($field, $value);
assertInputValueIsNot
Verifica che il campo input specificato non abbia il valore indicato:
$browser->assertInputValueIsNot($field, $value);
assertChecked
Verifica che la checkbox specificata sia selezionata:
$browser->assertChecked($field);
assertNotChecked
Assicura che il checkbox specificato non sia selezionato:
$browser->assertNotChecked($field);
assertIndeterminate
Verifica che la checkbox specificata sia in uno stato indeterminato:
$browser->assertIndeterminate($field);
assertRadioSelected
Verifica che il campo radio specificato sia selezionato:
$browser->assertRadioSelected($field, $value);
assertRadioNotSelected
Verifica che il campo radio specificato non sia selezionato:
$browser->assertRadioNotSelected($field, $value);
assertSelected
Verifica che il menu a tendina specificato abbia il valore dato selezionato:
$browser->assertSelected($field, $value);
assertNotSelected
Verifica che il dropdown specificato non abbia selezionato il valore dato:
$browser->assertNotSelected($field, $value);
assertSelectHasOptions
Verifica che l’array di valori fornito sia disponibile per la selezione:
$browser->assertSelectHasOptions($field, $values);
assertSelectMissingOptions
Verifica che l’array di valori fornito non sia disponibile per la selezione:
$browser->assertSelectMissingOptions($field, $values);
assertSelectHasOption
Verifica che il valore specificato sia disponibile per la selezione nel campo indicato:
$browser->assertSelectHasOption($field, $value);
assertSelectMissingOption
Verifica che il valore specificato non sia disponibile per la selezione:
$browser->assertSelectMissingOption($field, $value);
assertValue
Verifica che l’elemento che corrisponde al selettore dato abbia il valore specificato:
$browser->assertValue($selector, $value);
assertValueIsNot
Verifica che l’elemento corrispondente al selettore fornito non abbia il valore specificato:
$browser->assertValueIsNot($selector, $value);
assertAttribute
Verifica che l’elemento che corrisponde al selettore fornito abbia il valore specificato nell’attributo indicato:
$browser->assertAttribute($selector, $attribute, $value);
assertAttributeContains
Verifica che l’elemento che corrisponde al selettore dato contenga il valore specificato nell’attributo fornito:
$browser->assertAttributeContains($selector, $attribute, $value);
assertAttributeDoesntContain
Verifica che l’elemento corrispondente al selettore indicato non contenga il valore specificato nell’attributo fornito:
$browser->assertAttributeDoesntContain($selector, $attribute, $value);
assertAriaAttribute
Verifica che l’elemento che corrisponde al selettore fornito abbia il valore specificato nell’attributo aria indicato:
$browser->assertAriaAttribute($selector, $attribute, $value);
Ad esempio, dato il markup <button aria-label="Add"></button>
, puoi verificare l’attributo aria-label
in questo modo:
$browser->assertAriaAttribute('button', 'label', 'Add')
assertDataAttribute
Verifica che l’elemento che corrisponde al selettore dato abbia il valore specificato nell’attributo data fornito:
$browser->assertDataAttribute($selector, $attribute, $value);
Per esempio, dato il markup <tr id="row-1" data-content="attendees"></tr>
, puoi verificare l’attributo data-label
così:
$browser->assertDataAttribute('#row-1', 'content', 'attendees')
assertVisible
Verifica che l’elemento che corrisponde al selettore dato sia visibile:
$browser->assertVisible($selector);
assertPresent
Verifica che l’elemento corrispondente al selettore specificato sia presente nel sorgente:
$browser->assertPresent($selector);
assertNotPresent
Verifica che l’elemento che corrisponde al selettore dato non sia presente nel sorgente:
$browser->assertNotPresent($selector);
assertMissing
Verifica che l’elemento che corrisponde al selettore dato non sia visibile:
$browser->assertMissing($selector);
assertInputPresent
Verifica che un input con il nome specificato sia presente:
$browser->assertInputPresent($name);
assertInputMissing
Verifica che un input con il nome specificato non sia presente nella sorgente:
$browser->assertInputMissing($name);
assertDialogOpened
Controlla che sia stato aperto un dialogo JavaScript con il messaggio fornito:
$browser->assertDialogOpened($message);
assertEnabled
Verifica che il campo specificato sia abilitato:
$browser->assertEnabled($field);
assertDisabled
Verifica che il campo specificato sia disabilitato:
$browser->assertDisabled($field);
assertButtonEnabled
Verifica che il pulsante specificato sia abilitato:
$browser->assertButtonEnabled($button);
assertButtonDisabled
Verifica che il pulsante specificato sia disabilitato:
$browser->assertButtonDisabled($button);
assertFocused
Verifica che il campo specificato sia attivo:
$browser->assertFocused($field);
assertNotFocused
Verifica che il campo specificato non sia focalizzato:
$browser->assertNotFocused($field);
assertAuthenticated
Verifica che l’utente sia autenticato:
$browser->assertAuthenticated();
assertGuest
Verifica che l’utente non sia autenticato:
$browser->assertGuest();
assertAuthenticatedAs
Verifica che l’utente sia autenticato come l’utente specificato:
$browser->assertAuthenticatedAs($user);
assertVue
Dusk permette anche di fare asserzioni sullo stato dei dati di un componente Vue. Ad esempio, immagina che la tua applicazione contenga il seguente componente Vue:
// HTML...
<profile dusk="profile-component"></profile>
// Definizione del Componente...
Vue.component('profile', {
template: '<div>{{ user.name }}</div>',
data: function () {
return {
user: {
name: 'Taylor'
}
};
}
});
Puoi verificare lo stato del componente Vue in questo modo:
test('vue', function () {
$this->browse(function (Browser $browser) {
$browser->visit('/')
->assertVue('user.name', 'Taylor', '@profile-component');
});
});
/**
* Un esempio base di test Vue.
*/
public function test_vue(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/')
->assertVue('user.name', 'Taylor', '@profile-component');
});
}
assertVueIsNot
Verifica che una determinata proprietà dei dati di un componente Vue non corrisponda al valore specificato:
$browser->assertVueIsNot($property, $value, $componentSelector = null);
assertVueContains
Verifica che una determinata proprietà dati di un componente Vue sia un array e contenga il valore specificato:
$browser->assertVueContains($property, $value, $componentSelector = null);
assertVueDoesntContain
Verifica che una determinata proprietà dati di un componente Vue sia un array e non contenga il valore specificato:
$browser->assertVueDoesntContain($property, $value, $componentSelector = null);
Pagine
A volte, i test richiedono di eseguire diverse azioni complesse in sequenza. Questo può rendere i test più difficili da leggere e comprendere. Le Pagine Dusk ti permettono di definire azioni esplicative che possono essere eseguite su una determinata pagina tramite un unico metodo. Le pagine consentono anche di definire scorciatoie per selettori comuni della tua applicazione o di una singola pagina.
Generazione delle Pagine
Per creare un oggetto pagina, esegui il comando Artisan dusk:page
. Tutti gli oggetti pagina saranno posizionati nella directory tests/Browser/Pages
della tua applicazione:
php artisan dusk:page Login
Configurazione delle Pagine
Per impostazione predefinita, le pagine hanno tre metodi: url
, assert
ed elements
. Ora parleremo dei metodi url
e assert
. Il metodo elements
sarà discusso in maggior dettaglio più avanti.
Il metodo url
Il metodo url
dovrebbe restituire il percorso dell’URL che rappresenta la pagina. Dusk utilizzerà questo URL quando naviga alla pagina nel browser:
/**
* Ottieni l'URL per la pagina.
*/
public function url(): string
{
return '/login';
}
Il metodo assert
Il metodo assert
può effettuare qualsiasi asserzione necessaria per verificare che il browser sia effettivamente sulla pagina data. Non è necessario inserire nulla all’interno di questo metodo; tuttavia, puoi effettuare queste asserzioni se lo desideri. Queste asserzioni verranno eseguite automaticamente durante la navigazione alla pagina:
/**
* Assert that the browser is on the page.
*/
public function assert(Browser $browser): void
{
$browser->assertPathIs($this->url());
}
Navigare tra le Pagine
Una volta che una pagina è stata definita, puoi navigarci usando il metodo visit
:
use Tests\Browser\Pages\Login;
$browser->visit(new Login);
A volte potresti già trovarti in una pagina specifica e avere bisogno di "caricare" i selettori e i metodi della pagina nel contesto del test corrente. Questo è comune quando premi un pulsante e vieni reindirizzato a una pagina senza navigarci esplicitamente. In questa situazione, puoi usare il metodo on
per caricare la pagina:
use Tests\Browser\Pages\CreatePlaylist;
$browser->visit('/dashboard')
->clickLink('Create Playlist')
->on(new CreatePlaylist)
->assertSee('@create');
Selettori Abbreviati
Il metodo elements
all’interno delle classi delle pagine ti permette di definire scorciatoie veloci e facili da ricordare per qualsiasi selettore CSS sulla tua pagina. Per esempio, definiamo una scorciatoia per il campo di input "email" della pagina di login dell’applicazione:
/**
* Ottieni le scorciatoie degli elementi per la pagina.
*
* @return array<string, string>
*/
public function elements(): array
{
return [
'@email' => 'input[name=email]',
];
}
Una volta definita la scorciatoia, puoi usare il selettore abbreviato ovunque normalmente utilizzeresti un selettore CSS completo:
$browser->type('@email', 'taylor@laravel.com');
Selettori abbreviati globali
Dopo aver installato Dusk, una classe base Page
sarà posizionata nella directory tests/Browser/Pages
. Questa classe contiene un metodo siteElements
che può essere utilizzato per definire selettori abbreviati globali che dovrebbero essere disponibili su ogni pagina della tua applicazione:
/**
* Get the global element shortcuts for the site.
*
* @return array<string, string>
*/
public static function siteElements(): array
{
return [
'@element' => '#selector',
];
}
Metodi di Pagina
Oltre ai metodi predefiniti definiti nelle pagine, puoi definire metodi aggiuntivi che possono essere utilizzati in tutti i tuoi test. Ad esempio, immaginiamo di costruire un’applicazione per la gestione della musica. Un’azione comune per una pagina dell’applicazione potrebbe essere quella di creare una playlist. Invece di riscrivere la logica per creare una playlist in ogni test, puoi definire un metodo createPlaylist
in una classe di pagina:
<?php
namespace Tests\Browser\Pages;
use Laravel\Dusk\Browser;
use Laravel\Dusk\Page;
class Dashboard extends Page
{
// Altri metodi della pagina...
/**
* Crea una nuova playlist.
*/
public function createPlaylist(Browser $browser, string $name): void
{
$browser->type('name', $name)
->check('share')
->press('Create Playlist');
}
}
Una volta che il metodo è stato definito, puoi usarlo in qualsiasi test che utilizzi la pagina. L’istanza del browser verrà automaticamente passata come primo argomento ai metodi personalizzati della pagina:
use Tests\Browser\Pages\Dashboard;
$browser->visit(new Dashboard)
->createPlaylist('My Playlist')
->assertSee('My Playlist');
Componenti
I componenti sono simili ai “page objects” di Dusk, ma sono destinati a parti dell’interfaccia utente e funzionalità che vengono riutilizzate in tutta l’applicazione, come una barra di navigazione o una finestra di notifica. Per questo motivo, i componenti non sono legati a URL specifici.
Generazione dei Componenti
Per generare un componente, esegui il comando Artisan dusk:component
. I nuovi componenti vengono posizionati nella directory tests/Browser/Components
:
php artisan dusk:component DatePicker
Come mostrato sopra, un "date picker" è un esempio di componente che potrebbe essere presente in diverse pagine della tua applicazione. Scrivere manualmente la logica di automazione del browser per selezionare una data in decine di test può diventare complicato. Invece, possiamo definire un componente Dusk per rappresentare il date picker, permettendoci di incapsulare quella logica all’interno del componente:
<?php
namespace Tests\Browser\Components;
use Laravel\Dusk\Browser;
use Laravel\Dusk\Component as BaseComponent;
class DatePicker extends BaseComponent
{
/**
* Ottieni il selettore principale per il componente.
*/
public function selector(): string
{
return '.date-picker';
}
/**
* Verifica che la pagina del browser contenga il componente.
*/
public function assert(Browser $browser): void
{
$browser->assertVisible($this->selector());
}
/**
* Ottieni le scorciatoie degli elementi per il componente.
*
* @return array<string, string>
*/
public function elements(): array
{
return [
'@date-field' => 'input.datepicker-input',
'@year-list' => 'div > div.datepicker-years',
'@month-list' => 'div > div.datepicker-months',
'@day-list' => 'div > div.datepicker-days',
];
}
/**
* Seleziona la data specificata.
*/
public function selectDate(Browser $browser, int $year, int $month, int $day): void
{
$browser->click('@date-field')
->within('@year-list', function (Browser $browser) use ($year) {
$browser->click($year);
})
->within('@month-list', function (Browser $browser) use ($month) {
$browser->click($month);
})
->within('@day-list', function (Browser $browser) use ($day) {
$browser->click($day);
});
}
}
Utilizzo dei Componenti
Una volta che il componente è stato definito, possiamo facilmente selezionare una data all’interno del date picker da qualsiasi test. E, se la logica necessaria per selezionare una data cambia, dobbiamo solo aggiornare il componente:
<?php
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
use Tests\Browser\Components\DatePicker;
uses(DatabaseMigrations::class);
test('basic example', function () {
$this->browse(function (Browser $browser) {
$browser->visit('/')
->within(new DatePicker, function (Browser $browser) {
$browser->selectDate(2019, 1, 30);
})
->assertSee('January');
});
});
<?php
namespace Tests\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
use Tests\Browser\Components\DatePicker;
use Tests\DuskTestCase;
class ExampleTest extends DuskTestCase
{
/**
* A basic component test example.
*/
public function test_basic_example(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/')
->within(new DatePicker, function (Browser $browser) {
$browser->selectDate(2019, 1, 30);
})
->assertSee('January');
});
}
}
Integrazione Continua
La maggior parte delle configurazioni di integrazione continua di Dusk si aspetta che la tua applicazione Laravel venga servita utilizzando il server di sviluppo PHP integrato sulla porta 8000. Pertanto, prima di procedere, assicurati che il tuo ambiente di integrazione continua abbia una variabile d’ambiente
APP_URL
con valorehttp://127.0.0.1:8000
.
Heroku CI
Per eseguire i test Dusk su Heroku CI, aggiungi il seguente buildpack di Google Chrome e gli script al file app.json
della tua app Heroku:
{
"environments": {
"test": {
"buildpacks": [
{ "url": "heroku/php" },
{ "url": "https://github.com/heroku/heroku-buildpack-chrome-for-testing" }
],
"scripts": {
"test-setup": "cp .env.testing .env",
"test": "nohup bash -c './vendor/laravel/dusk/bin/chromedriver-linux --port=9515 > /dev/null 2>&1 &' && nohup bash -c 'php artisan serve --no-reload > /dev/null 2>&1 &' && php artisan dusk"
}
}
}
}
Travis CI
Per eseguire i tuoi test Dusk su Travis CI, utilizza la seguente configurazione .travis.yml
. Poiché Travis CI non è un ambiente grafico, sarà necessario eseguire alcuni passaggi aggiuntivi per avviare un browser Chrome. Inoltre, useremo php artisan serve
per avviare il server web integrato di PHP:
language: php
php:
- 8.2
addons:
chrome: stable
install:
- cp .env.testing .env
- travis_retry composer install --no-interaction --prefer-dist
- php artisan key:generate
- php artisan dusk:chrome-driver
before_script:
- google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost &
- php artisan serve --no-reload &
script:
- php artisan dusk
GitHub Actions
Se stai usando GitHub Actions per eseguire i tuoi test Dusk, puoi utilizzare il seguente file di configurazione come punto di partenza. Come con TravisCI, useremo il comando php artisan serve
per avviare il server web integrato di PHP:
name: CI
on: [push]
jobs:
dusk-php:
runs-on: ubuntu-latest
env:
APP_URL: "http://127.0.0.1:8000"
DB_USERNAME: root
DB_PASSWORD: root
MAIL_MAILER: log
steps:
- uses: actions/checkout@v4
- name: Prepara l'Ambiente
run: cp .env.example .env
- name: Crea il Database
run: |
sudo systemctl start mysql
mysql --user="root" --password="root" -e "CREATE DATABASE \`my-database\` character set UTF8mb4 collate utf8mb4_bin;"
- name: Installa le Dipendenze di Composer
run: composer install --no-progress --prefer-dist --optimize-autoloader
- name: Genera la Chiave dell'Applicazione
run: php artisan key:generate
- name: Aggiorna il Chrome Driver
run: php artisan dusk:chrome-driver --detect
- name: Avvia il Chrome Driver
run: ./vendor/laravel/dusk/bin/chromedriver-linux --port=9515 &
- name: Avvia il Server Laravel
run: php artisan serve --no-reload &
- name: Esegui i Test Dusk
run: php artisan dusk
- name: Carica gli Screenshot
if: failure()
uses: actions/upload-artifact@v4
with:
name: screenshots
path: tests/Browser/screenshots
- name: Carica i Log della Console
if: failure()
uses: actions/upload-artifact@v4
with:
name: console
path: tests/Browser/console
Chipper CI
Se stai usando Chipper CI per eseguire i tuoi test Dusk, puoi utilizzare il seguente file di configurazione come punto di partenza. Useremo il server integrato di PHP per eseguire Laravel in modo da poter ascoltare le richieste:
# file .chipperci.yml
version: 1
environment:
php: 8.2
node: 16
# Include Chrome in the build environment
services:
- dusk
# Build all commits
on:
push:
branches: .*
pipeline:
- name: Setup
cmd: |
cp -v .env.example .env
composer install --no-interaction --prefer-dist --optimize-autoloader
php artisan key:generate
# Create a dusk env file, ensuring APP_URL uses BUILD_HOST
cp -v .env .env.dusk.ci
sed -i "s@APP_URL=.*@APP_URL=http://$BUILD_HOST:8000@g" .env.dusk.ci
- name: Compile Assets
cmd: |
npm ci --no-audit
npm run build
- name: Browser Tests
cmd: |
php -S [::0]:8000 -t public 2>server.log &
sleep 2
php artisan dusk:chrome-driver $CHROME_DRIVER
php artisan dusk --env=ci