- Introducción
- Instalación
- Primeros pasos
- Conceptos básicos del navegador
- Interacción con elementos
- Aserciones disponibles
- Páginas
- Componentes
- Integración continua
#Introducción
Laravel Dusk ofrece una API expresiva y fácil de usar para la automatización y pruebas en navegador. Por defecto, Dusk no requiere que instale JDK o Selenium en su computadora local. En su lugar, Dusk utiliza una instalación independiente de ChromeDriver. Sin embargo, usted es libre de utilizar cualquier otro controlador compatible con Selenium que desee.
#Instalación
Para comenzar, debe instalar Google Chrome y agregar la dependencia laravel/dusk de Composer a su proyecto:
composer require laravel/dusk --dev
Si registra manualmente el proveedor de servicios de Dusk, nunca debe registrarlo en su entorno de producción, ya que esto podría permitir que usuarios arbitrarios se autentiquen en su aplicación.
Después de instalar el paquete Dusk, ejecute el comando Artisan dusk:install. El comando dusk:install creará un directorio tests/Browser, una prueba de ejemplo de Dusk y instalará el binario de Chrome Driver para su sistema operativo:
php artisan dusk:install
Luego, configure la variable de entorno APP_URL en el archivo .env de su aplicación. Este valor debe coincidir con la URL que utiliza para acceder a su aplicación en un navegador.
Si utiliza Laravel Sail para administrar su entorno de desarrollo local, consulte también la documentación de Sail sobre configuración y ejecución de pruebas Dusk.
#Gestión de instalaciones de ChromeDriver
Si desea instalar una versión diferente de ChromeDriver a la que instala Laravel Dusk mediante el comando dusk:install, puede usar el comando dusk:chrome-driver:
# Instalar la última versión de ChromeDriver para su SO...
php artisan dusk:chrome-driver
# Instalar una versión específica de ChromeDriver para su SO...
php artisan dusk:chrome-driver 86
# Instalar una versión específica de ChromeDriver para todos los SO soportados...
php artisan dusk:chrome-driver --all
# Instalar la versión de ChromeDriver que coincide con la versión detectada de Chrome / Chromium para su SO...
php artisan dusk:chrome-driver --detect
Dusk requiere que los binarios chromedriver sean ejecutables. Si tiene problemas para ejecutar Dusk, asegúrese de que los binarios sean ejecutables usando el siguiente comando: chmod -R 0755 vendor/laravel/dusk/bin/.
#Uso de otros navegadores
Por defecto, Dusk utiliza Google Chrome y una instalación independiente de ChromeDriver para ejecutar sus pruebas en navegador. Sin embargo, puede iniciar su propio servidor Selenium y ejecutar las pruebas en cualquier navegador que desee.
Para comenzar, abra el archivo tests/DuskTestCase.php, que es la clase base de pruebas Dusk para su aplicación. En este archivo, puede eliminar la llamada al método startChromeDriver. Esto evitará que Dusk inicie automáticamente ChromeDriver:
/**
* Preparar para la ejecución de pruebas Dusk.
*
* @beforeClass
*/
public static function prepare(): void
{
// static::startChromeDriver();
}
Luego, puede modificar el método driver para conectarse a la URL y puerto que prefiera. Además, puede modificar las "capacidades deseadas" que se deben pasar al WebDriver:
use Facebook\WebDriver\Remote\RemoteWebDriver;
/**
* Crear la instancia RemoteWebDriver.
*/
protected function driver(): RemoteWebDriver
{
return RemoteWebDriver::create(
'http://localhost:4444/wd/hub', DesiredCapabilities::phantomjs()
);
}
#Primeros pasos
#Generación de pruebas
Para generar una prueba Dusk, use el comando Artisan dusk:make. La prueba generada se colocará en el directorio tests/Browser:
php artisan dusk:make LoginTest
#Restablecer la base de datos después de cada prueba
La mayoría de las pruebas que escriba interaccionarán con páginas que obtienen datos de la base de datos de su aplicación; sin embargo, sus pruebas de Dusk nunca deberían usar el RefreshDatabase trait. El RefreshDatabase trait aprovecha las transacciones de la base de datos, las cuales no son aplicables ni estarán disponibles a través de solicitudes HTTP. En su lugar, tiene dos opciones: el DatabaseMigrations trait y el DatabaseTruncation trait.
#Uso de migraciones de base de datos
El trait DatabaseMigrations ejecutará sus migraciones de base de datos antes de cada prueba. Sin embargo, eliminar y volver a crear las tablas de la base de datos para cada prueba suele ser más lento que truncar las tablas:
<?php
namespace Tests\Browser;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Chrome;
use Tests\DuskTestCase;
class ExampleTest extends DuskTestCase
{
use DatabaseMigrations;
}
No se pueden usar bases de datos SQLite en memoria al ejecutar pruebas Dusk. Dado que el navegador se ejecuta en su propio proceso, no podrá acceder a las bases de datos en memoria de otros procesos.
#Uso de truncamiento de base de datos
Antes de usar el trait DatabaseTruncation, debe instalar el paquete doctrine/dbal usando el gestor de paquetes Composer:
composer require --dev doctrine/dbal
El trait DatabaseTruncation migrará su base de datos en la primera prueba para asegurar que las tablas se hayan creado correctamente. Sin embargo, en pruebas posteriores, las tablas simplemente se truncarán, lo que proporciona una mejora de velocidad frente a volver a ejecutar todas las migraciones:
<?php
namespace Tests\Browser;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTruncation;
use Laravel\Dusk\Chrome;
use Tests\DuskTestCase;
class ExampleTest extends DuskTestCase
{
use DatabaseTruncation;
}
Por defecto, este trait truncará todas las tablas excepto la tabla migrations. Si desea personalizar las tablas que deben truncarse, puede definir una propiedad $tablesToTruncate en su clase de prueba:
/**
* Indica qué tablas deben truncarse.
*
* @var array
*/
protected $tablesToTruncate = ['users'];
Alternativamente, puede definir una propiedad $exceptTables en su clase de prueba para especificar qué tablas deben excluirse del truncamiento:
/**
* Indica qué tablas deben excluirse del truncamiento.
*
* @var array
*/
protected $exceptTables = ['users'];
Para especificar las conexiones de base de datos cuyas tablas deben truncarse, puede definir una propiedad $connectionsToTruncate en su clase de prueba:
/**
* Indica qué conexiones deben tener sus tablas truncadas.
*
* @var array
*/
protected $connectionsToTruncate = ['mysql'];
Si desea ejecutar código antes o después de que se realice el truncamiento de la base de datos, puede definir los métodos beforeTruncatingDatabase o afterTruncatingDatabase en su clase de prueba:
/**
* Realizar cualquier trabajo que deba ocurrir antes de que la base de datos comience a truncarse.
*/
protected function beforeTruncatingDatabase(): void
{
//
}
/**
* Realizar cualquier trabajo que deba ocurrir después de que la base de datos haya terminado de truncarse.
*/
protected function afterTruncatingDatabase(): void
{
//
}
#Ejecución de pruebas
Para ejecutar sus pruebas en navegador, ejecute el comando Artisan dusk:
php artisan dusk
Si tuvo fallos en las pruebas la última vez que ejecutó el comando dusk, puede ahorrar tiempo volviendo a ejecutar primero las pruebas que fallaron usando el comando dusk:fails:
php artisan dusk:fails
El comando dusk acepta cualquier argumento que normalmente acepte el ejecutor de pruebas PHPUnit, como permitir ejecutar solo las pruebas de un grupo dado:
php artisan dusk --group=foo
Si utiliza Laravel Sail para administrar su entorno de desarrollo local, consulte la documentación de Sail sobre configuración y ejecución de pruebas Dusk.
#Inicio manual de ChromeDriver
Por defecto, Dusk intentará iniciar automáticamente ChromeDriver. Si esto no funciona en su sistema, puede iniciar ChromeDriver manualmente antes de ejecutar el comando dusk. Si elige iniciar ChromeDriver manualmente, debe comentar la siguiente línea en su archivo tests/DuskTestCase.php:
/**
* Preparar para la ejecución de pruebas Dusk.
*
* @beforeClass
*/
public static function prepare(): void
{
// static::startChromeDriver();
}
Además, si inicia ChromeDriver en un puerto distinto al 9515, debe modificar el método driver de la misma clase para reflejar el puerto correcto:
use Facebook\WebDriver\Remote\RemoteWebDriver;
/**
* Crear la instancia RemoteWebDriver.
*/
protected function driver(): RemoteWebDriver
{
return RemoteWebDriver::create(
'http://localhost:9515', DesiredCapabilities::chrome()
);
}
#Manejo del entorno
Para forzar que Dusk use su propio archivo de entorno al ejecutar pruebas, cree un archivo .env.dusk.{environment} en la raíz de su proyecto. Por ejemplo, si va a iniciar el comando dusk desde su entorno local, debe crear un archivo .env.dusk.local.
Al ejecutar las pruebas, Dusk hará una copia de seguridad de su archivo .env y renombrará su entorno Dusk a .env. Una vez que las pruebas hayan finalizado, su archivo .env será restaurado.
#Conceptos básicos del navegador
#Creación de navegadores
Para comenzar, escribamos una prueba que verifique que podemos iniciar sesión en nuestra aplicación. Después de generar una prueba, podemos modificarla para navegar a la página de inicio de sesión, ingresar algunas credenciales y hacer clic en el botón "Login". Para crear una instancia de navegador, puede llamar al método browse dentro de su prueba Dusk:
<?php
namespace Tests\Browser;
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
use Laravel\Dusk\Chrome;
use Tests\DuskTestCase;
class ExampleTest extends DuskTestCase
{
use DatabaseMigrations;
/**
* Un ejemplo básico de prueba en navegador.
*/
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');
});
}
}
Como puede ver en el ejemplo anterior, el método browse acepta un closure. Dusk pasará automáticamente una instancia de navegador a este closure, que es el objeto principal usado para interactuar y hacer aserciones contra su aplicación.
#Creación de múltiples navegadores
A veces puede necesitar múltiples navegadores para realizar correctamente una prueba. Por ejemplo, puede necesitar varios navegadores para probar una pantalla de chat que interactúa con websockets. Para crear múltiples navegadores, simplemente agregue más argumentos de navegador a la firma del closure pasado al método 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');
});
#Navegación
El método visit puede usarse para navegar a una URI dada dentro de su aplicación:
$browser->visit('/login');
Puede usar el método visitRoute para navegar a una ruta nombrada:
$browser->visitRoute('login');
Puede navegar "atrás" y "adelante" usando los métodos back y forward:
$browser->back();
$browser->forward();
Puede usar el método refresh para actualizar la página:
$browser->refresh();
#Redimensionar ventanas del navegador
Puede usar el método resize para ajustar el tamaño de la ventana del navegador:
$browser->resize(1920, 1080);
El método maximize puede usarse para maximizar la ventana del navegador:
$browser->maximize();
El método fitContent redimensionará la ventana del navegador para que coincida con el tamaño de su contenido:
$browser->fitContent();
Cuando una prueba falla, Dusk redimensiona automáticamente el navegador para ajustarlo al contenido antes de tomar una captura de pantalla. Puede desactivar esta función llamando al método disableFitOnFailure dentro de su prueba:
$browser->disableFitOnFailure();
Puede usar el método move para mover la ventana del navegador a una posición diferente en su pantalla:
$browser->move($x = 100, $y = 100);
#Macros del navegador
Si desea definir un método personalizado para el navegador que pueda reutilizar en varias pruebas, puede usar el método macro en la clase Browser. Normalmente, debe llamar a este método desde el método boot de un service provider:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Laravel\Dusk\Browser;
class DuskServiceProvider extends ServiceProvider
{
/**
* Registrar las macros del navegador 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 función macro acepta un nombre como primer argumento y un closure como segundo. El closure de la macro se ejecutará al llamar a la macro como método en una instancia de Browser:
$this->browse(function (Browser $browser) use ($user) {
$browser->visit('/pay')
->scrollToElement('#credit-card-details')
->assertSee('Enter Credit Card Details');
});
#Autenticación
A menudo, probará páginas que requieren autenticación. Puede usar el método loginAs de Dusk para evitar interactuar con la pantalla de inicio de sesión de su aplicación en cada prueba. El método loginAs acepta una clave primaria asociada con su modelo autenticable o una instancia del modelo autenticable:
use App\Models\User;
use Laravel\Dusk\Browser;
$this->browse(function (Browser $browser) {
$browser->loginAs(User::find(1))
->visit('/home');
});
Después de usar el método loginAs, la sesión del usuario se mantendrá para todas las pruebas dentro del archivo.
#Cookies
Puede usar el método cookie para obtener o establecer el valor de una cookie cifrada. Por defecto, todas las cookies creadas por Laravel están cifradas:
$browser->cookie('name');
$browser->cookie('name', 'Taylor');
Puede usar el método plainCookie para obtener o establecer el valor de una cookie sin cifrar:
$browser->plainCookie('name');
$browser->plainCookie('name', 'Taylor');
Puede usar el método deleteCookie para eliminar la cookie indicada:
$browser->deleteCookie('name');
#Ejecución de JavaScript
Puede usar el método script para ejecutar sentencias arbitrarias de JavaScript dentro del navegador:
$browser->script('document.documentElement.scrollTop = 0');
$browser->script([
'document.body.scrollTop = 0',
'document.documentElement.scrollTop = 0',
]);
$output = $browser->script('return window.location.pathname');
#Captura de pantalla
Puede usar el método screenshot para tomar una captura de pantalla y guardarla con el nombre de archivo indicado. Todas las capturas se almacenarán en el directorio tests/Browser/screenshots:
$browser->screenshot('filename');
El método responsiveScreenshots puede usarse para tomar una serie de capturas en varios puntos de ruptura:
$browser->responsiveScreenshots('filename');
#Guardar salida de consola en disco
Puede usar el método storeConsoleLog para escribir la salida actual de la consola del navegador en disco con el nombre de archivo indicado. La salida de consola se almacenará en el directorio tests/Browser/console:
$browser->storeConsoleLog('filename');
#Guardar código fuente de la página en disco
Puede usar el método storeSource para escribir el código fuente actual de la página en disco con el nombre de archivo indicado. El código fuente se almacenará en el directorio tests/Browser/source:
$browser->storeSource('filename');
#Interacción con elementos
#Selectores Dusk
Elegir buenos selectores CSS para interactuar con elementos es una de las partes más difíciles al escribir pruebas Dusk. Con el tiempo, los cambios en el frontend pueden hacer que selectores CSS como los siguientes rompan sus pruebas:
// HTML...
<button>Login</button>
// Prueba...
$browser->click('.login-page .container div > button');
Los selectores Dusk le permiten centrarse en escribir pruebas efectivas en lugar de recordar selectores CSS. Para definir un selector, agregue un atributo dusk a su elemento HTML. Luego, al interactuar con un navegador Dusk, anteponga el selector con @ para manipular el elemento adjunto dentro de su prueba:
// HTML...
<button dusk="login-button">Login</button>
// Prueba...
$browser->click('@login-button');
Si lo desea, puede personalizar el atributo HTML que utiliza el selector Dusk mediante el método selectorHtmlAttribute. Normalmente, este método debe llamarse desde el método boot del AppServiceProvider de su aplicación:
use Laravel\Dusk\Dusk;
Dusk::selectorHtmlAttribute('data-dusk');
#Texto, valores y atributos
#Recuperar y establecer valores
Dusk proporciona varios métodos para interactuar con el valor actual, el texto visible y los atributos de los elementos en la página. Por ejemplo, para obtener el "valor" de un elemento que coincide con un selector CSS o Dusk dado, use el método value:
// Recuperar el valor...
$value = $browser->value('selector');
// Establecer el valor...
$browser->value('selector', 'value');
Puede usar el método inputValue para obtener el "valor" de un elemento input que tiene un nombre de campo dado:
$value = $browser->inputValue('field');
#Recuperar texto
El método text puede usarse para recuperar el texto visible de un elemento que coincide con el selector dado:
$text = $browser->text('selector');
#Recuperar atributos
Finalmente, el método attribute puede usarse para recuperar el valor de un atributo de un elemento que coincide con el selector dado:
$attribute = $browser->attribute('selector', 'value');
#Interacción con formularios
#Escribir valores
Dusk proporciona varios métodos para interactuar con formularios y elementos input. Primero, veamos un ejemplo de cómo escribir texto en un campo input:
$browser->type('email', 'taylor@laravel.com');
Tenga en cuenta que, aunque el método acepta un selector CSS si es necesario, no es obligatorio pasar un selector CSS al método type. Si no se proporciona un selector CSS, Dusk buscará un campo input o textarea con el atributo name dado.
Para agregar texto a un campo sin borrar su contenido, puede usar el método append:
$browser->type('tags', 'foo')
->append('tags', ', bar, baz');
Puede borrar el valor de un input usando el método clear:
$browser->clear('email');
Puede indicarle a Dusk que escriba lentamente usando el método typeSlowly. Por defecto, Dusk pausará 100 milisegundos entre pulsaciones de tecla. Para personalizar el tiempo entre pulsaciones, puede pasar el número apropiado de milisegundos como tercer argumento al método:
$browser->typeSlowly('mobile', '+1 (202) 555-5555');
$browser->typeSlowly('mobile', '+1 (202) 555-5555', 300);
Puede usar el método appendSlowly para agregar texto lentamente:
$browser->type('tags', 'foo')
->appendSlowly('tags', ', bar, baz');
#Listas desplegables
Para seleccionar un valor disponible en un elemento select, puede usar el método select. Al igual que el método type, el método select no requiere un selector CSS completo. Al pasar un valor al método select, debe pasar el valor subyacente de la opción en lugar del texto visible:
$browser->select('size', 'Large');
Puede seleccionar una opción aleatoria omitiendo el segundo argumento:
$browser->select('size');
Al proporcionar un array como segundo argumento al método select, puede indicar que se seleccionen múltiples opciones:
$browser->select('categories', ['Art', 'Music']);
#Casillas de verificación
Para "marcar" una casilla de verificación, puede usar el método check. Al igual que muchos otros métodos relacionados con inputs, no se requiere un selector CSS completo. Si no se encuentra un selector CSS, Dusk buscará una casilla con un atributo name coincidente:
$browser->check('terms');
El método uncheck puede usarse para "desmarcar" una casilla de verificación:
$browser->uncheck('terms');
#Botones de opción (radio)
Para "seleccionar" una opción radio, puede usar el método radio. Al igual que muchos otros métodos relacionados con inputs, no se requiere un selector CSS completo. Si no se encuentra un selector CSS, Dusk buscará un input radio con atributos name y value coincidentes:
$browser->radio('size', 'large');
#Adjuntar archivos
El método attach puede usarse para adjuntar un archivo a un elemento input de tipo file. Al igual que muchos otros métodos relacionados con inputs, no se requiere un selector CSS completo. Si no se encuentra un selector CSS, Dusk buscará un input file con un atributo name coincidente:
$browser->attach('photo', __DIR__.'/photos/mountains.png');
La función attach requiere que la extensión PHP Zip esté instalada y habilitada en su servidor.
#Presionar botones
El método press puede usarse para hacer clic en un botón en la página. El argumento dado al método press puede ser el texto visible del botón o un selector CSS / Dusk:
$browser->press('Login');
Al enviar formularios, muchas aplicaciones deshabilitan el botón de envío del formulario después de presionarlo y luego vuelven a habilitar el botón cuando la solicitud HTTP del envío del formulario se completa. Para presionar un botón y esperar a que se vuelva a habilitar, puede usar el método pressAndWaitFor:
// Presione el botón y espere un máximo de 5 segundos para que se habilite...
$browser->pressAndWaitFor('Save');
// Presione el botón y espere un máximo de 1 segundo para que se habilite...
$browser->pressAndWaitFor('Save', 1);
#Hacer clic en enlaces
Para hacer clic en un enlace, puede usar el método clickLink en la instancia del navegador. El método clickLink hará clic en el enlace que tenga el texto visible dado:
$browser->clickLink($linkText);
Puede usar el método seeLink para determinar si un enlace con el texto visible dado es visible en la página:
if ($browser->seeLink($linkText)) {
// ...
}
Estos métodos interactúan con jQuery. Si jQuery no está disponible en la página, Dusk lo inyectará automáticamente para que esté disponible durante la duración de la prueba.
#Uso del teclado
El método keys le permite proporcionar secuencias de entrada más complejas a un elemento dado que las permitidas normalmente por el método type. Por ejemplo, puede indicarle a Dusk que mantenga presionadas teclas modificadoras mientras ingresa valores. En este ejemplo, la tecla shift se mantendrá presionada mientras se escribe taylor en el elemento que coincide con el selector dado. Después de escribir taylor, se escribirá swift sin teclas modificadoras:
$browser->keys('selector', ['{shift}', 'taylor'], 'swift');
Otro caso de uso valioso para el método keys es enviar una combinación de "atajo de teclado" al selector CSS principal de su aplicación:
$browser->keys('.app', ['{command}', 'j']);
Todas las teclas modificadoras como {command} están envueltas en caracteres {}, y coinciden con las constantes definidas en la clase Facebook\WebDriver\WebDriverKeys, que puede ser encontrada en GitHub.
#Interacciones de teclado fluidas
Dusk también proporciona un método withKeyboard, que le permite realizar interacciones complejas con el teclado de forma fluida mediante la clase Laravel\Dusk\Keyboard. La clase Keyboard ofrece los métodos press, release, type y pause:
use Laravel\Dusk\Keyboard;
$browser->withKeyboard(function (Keyboard $keyboard) {
$keyboard->press('c')
->pause(1000)
->release('c')
->type(['c', 'e', 'o']);
});
#Macros de teclado
Si desea definir interacciones de teclado personalizadas que pueda reutilizar fácilmente en toda su suite de pruebas, puede usar el método macro proporcionado por la clase Keyboard. Normalmente, debería llamar a este método desde el método boot de un service provider:
<?php
namespace App\Providers;
use Facebook\WebDriver\WebDriverKeys;
use Illuminate\Support\ServiceProvider;
use Laravel\Dusk\Keyboard;
use Laravel\Dusk\OperatingSystem;
class DuskServiceProvider extends ServiceProvider
{
/**
* Registrar las macros del navegador de 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 función macro acepta un nombre como primer argumento y un closure como segundo. El closure de la macro se ejecutará al llamar a la macro como un método en una instancia de Keyboard:
$browser->click('@textarea')
->withKeyboard(fn (Keyboard $keyboard) => $keyboard->copy())
->click('@another-textarea')
->withKeyboard(fn (Keyboard $keyboard) => $keyboard->paste());
#Uso del ratón
#Hacer clic en elementos
El método click puede usarse para hacer clic en un elemento que coincida con el selector CSS o Dusk dado:
$browser->click('.selector');
El método clickAtXPath puede usarse para hacer clic en un elemento que coincida con la expresión XPath dada:
$browser->clickAtXPath('//div[@class = "selector"]');
El método clickAtPoint puede usarse para hacer clic en el elemento más arriba en una pareja de coordenadas relativa al área visible del navegador:
$browser->clickAtPoint($x = 0, $y = 0);
El método doubleClick puede usarse para simular un doble clic del ratón:
$browser->doubleClick();
$browser->doubleClick('.selector');
El método rightClick puede usarse para simular un clic derecho del ratón:
$browser->rightClick();
$browser->rightClick('.selector');
El método clickAndHold puede usarse para simular que un botón del ratón está presionado y mantenido. Una llamada posterior al método releaseMouse revertirá este comportamiento y soltará el botón del ratón:
$browser->clickAndHold('.selector');
$browser->clickAndHold()
->pause(1000)
->releaseMouse();
El método controlClick puede usarse para simular el evento ctrl+click dentro del navegador:
$browser->controlClick();
$browser->controlClick('.selector');
#Mouseover
El método mouseover puede usarse cuando necesite mover el ratón sobre un elemento que coincida con el selector CSS o Dusk dado:
$browser->mouseover('.selector');
#Arrastrar y soltar
El método drag puede usarse para arrastrar un elemento que coincida con el selector dado hacia otro elemento:
$browser->drag('.from-selector', '.to-selector');
O puede arrastrar un elemento en una sola dirección:
$browser->dragLeft('.selector', $pixels = 10);
$browser->dragRight('.selector', $pixels = 10);
$browser->dragUp('.selector', $pixels = 10);
$browser->dragDown('.selector', $pixels = 10);
Finalmente, puede arrastrar un elemento por un desplazamiento dado:
$browser->dragOffset('.selector', $x = 10, $y = 10);
#Diálogos de JavaScript
Dusk proporciona varios métodos para interactuar con diálogos de JavaScript. Por ejemplo, puede usar el método waitForDialog para esperar a que aparezca un diálogo de JavaScript. Este método acepta un argumento opcional que indica cuántos segundos esperar para que aparezca el diálogo:
$browser->waitForDialog($seconds = null);
El método assertDialogOpened puede usarse para afirmar que un diálogo ha sido mostrado y contiene el mensaje dado:
$browser->assertDialogOpened('Dialog message');
Si el diálogo de JavaScript contiene un prompt, puede usar el método typeInDialog para escribir un valor en el prompt:
$browser->typeInDialog('Hello World');
Para cerrar un diálogo de JavaScript abierto haciendo clic en el botón "OK", puede invocar el método acceptDialog:
$browser->acceptDialog();
Para cerrar un diálogo de JavaScript abierto haciendo clic en el botón "Cancel", puede invocar el método dismissDialog:
$browser->dismissDialog();
#Interactuando con frames inline
Si necesita interactuar con elementos dentro de un iframe, puede usar el método withinFrame. Todas las interacciones con elementos que ocurran dentro del closure proporcionado al método withinFrame estarán limitadas al contexto del iframe especificado:
$browser->withinFrame('#credit-card-details', function ($browser) {
$browser->type('input[name="cardnumber"]', '4242424242424242')
->type('input[name="exp-date"]', '12/24')
->type('input[name="cvc"]', '123');
})->press('Pay');
});
#Limitando el alcance de selectores
A veces puede desear realizar varias operaciones limitando todas las operaciones dentro de un selector dado. Por ejemplo, puede querer afirmar que cierto texto existe solo dentro de una tabla y luego hacer clic en un botón dentro de esa tabla. Puede usar el método with para lograr esto. Todas las operaciones realizadas dentro del closure dado al método with estarán limitadas al selector original:
$browser->with('.table', function (Browser $table) {
$table->assertSee('Hello World')
->clickLink('Delete');
});
Ocasionalmente puede necesitar ejecutar afirmaciones fuera del alcance actual. Puede usar los métodos elsewhere y elsewhereWhenAvailable para lograr esto:
$browser->with('.table', function (Browser $table) {
// El alcance actual es `body .table`...
$browser->elsewhere('.page-title', function (Browser $title) {
// El alcance actual es `body .page-title`...
$title->assertSee('Hello World');
});
$browser->elsewhereWhenAvailable('.page-title', function (Browser $title) {
// El alcance actual es `body .page-title`...
$title->assertSee('Hello World');
});
});
#Esperando elementos
Al probar aplicaciones que usan JavaScript extensivamente, a menudo es necesario "esperar" a que ciertos elementos o datos estén disponibles antes de continuar con una prueba. Dusk facilita esto. Usando varios métodos, puede esperar a que los elementos se vuelvan visibles en la página o incluso esperar hasta que una expresión JavaScript dada evalúe a true.
#Esperar
Si solo necesita pausar la prueba por un número dado de milisegundos, use el método pause:
$browser->pause(1000);
Si necesita pausar la prueba solo si una condición dada es true, use el método pauseIf:
$browser->pauseIf(App::environment('production'), 1000);
De igual forma, si necesita pausar la prueba a menos que una condición dada sea true, puede usar el método pauseUnless:
$browser->pauseUnless(App::environment('testing'), 1000);
#Esperar selectores
El método waitFor puede usarse para pausar la ejecución de la prueba hasta que el elemento que coincida con el selector CSS o Dusk dado se muestre en la página. Por defecto, esto pausará la prueba por un máximo de cinco segundos antes de lanzar una excepción. Si es necesario, puede pasar un umbral de tiempo personalizado como segundo argumento al método:
// Esperar un máximo de cinco segundos por el selector...
$browser->waitFor('.selector');
// Esperar un máximo de un segundo por el selector...
$browser->waitFor('.selector', 1);
También puede esperar hasta que el elemento que coincida con el selector dado contenga el texto dado:
// Esperar un máximo de cinco segundos para que el selector contenga el texto dado...
$browser->waitForTextIn('.selector', 'Hello World');
// Esperar un máximo de un segundo para que el selector contenga el texto dado...
$browser->waitForTextIn('.selector', 'Hello World', 1);
También puede esperar hasta que el elemento que coincida con el selector dado desaparezca de la página:
// Esperar un máximo de cinco segundos hasta que el selector desaparezca...
$browser->waitUntilMissing('.selector');
// Esperar un máximo de un segundo hasta que el selector desaparezca...
$browser->waitUntilMissing('.selector', 1);
O puede esperar hasta que el elemento que coincida con el selector dado esté habilitado o deshabilitado:
// Esperar un máximo de cinco segundos hasta que el selector esté habilitado...
$browser->waitUntilEnabled('.selector');
// Esperar un máximo de un segundo hasta que el selector esté habilitado...
$browser->waitUntilEnabled('.selector', 1);
// Esperar un máximo de cinco segundos hasta que el selector esté deshabilitado...
$browser->waitUntilDisabled('.selector');
// Esperar un máximo de un segundo hasta que el selector esté deshabilitado...
$browser->waitUntilDisabled('.selector', 1);
#Limitar el alcance de selectores cuando estén disponibles
Ocasionalmente, puede desear esperar a que aparezca un elemento que coincida con un selector dado y luego interactuar con el elemento. Por ejemplo, puede querer esperar hasta que una ventana modal esté disponible y luego presionar el botón "OK" dentro de la modal. El método whenAvailable puede usarse para lograr esto. Todas las operaciones con elementos realizadas dentro del closure dado estarán limitadas al selector original:
$browser->whenAvailable('.modal', function (Browser $modal) {
$modal->assertSee('Hello World')
->press('OK');
});
#Esperar texto
El método waitForText puede usarse para esperar hasta que el texto dado se muestre en la página:
// Esperar un máximo de cinco segundos por el texto...
$browser->waitForText('Hello World');
// Esperar un máximo de un segundo por el texto...
$browser->waitForText('Hello World', 1);
Puede usar el método waitUntilMissingText para esperar hasta que el texto mostrado haya sido removido de la página:
// Esperar un máximo de cinco segundos para que el texto sea removido...
$browser->waitUntilMissingText('Hello World');
// Esperar un máximo de un segundo para que el texto sea removido...
$browser->waitUntilMissingText('Hello World', 1);
#Esperar enlaces
El método waitForLink puede usarse para esperar hasta que el texto del enlace dado se muestre en la página:
// Esperar un máximo de cinco segundos por el enlace...
$browser->waitForLink('Create');
// Esperar un máximo de un segundo por el enlace...
$browser->waitForLink('Create', 1);
#Esperar inputs
El método waitForInput puede usarse para esperar hasta que el campo de entrada dado sea visible en la página:
// Esperar un máximo de cinco segundos por el input...
$browser->waitForInput($field);
// Esperar un máximo de un segundo por el input...
$browser->waitForInput($field, 1);
#Esperar la ubicación de la página
Al hacer una afirmación de ruta como $browser->assertPathIs('/home'), la afirmación puede fallar si window.location.pathname se está actualizando de forma asíncrona. Puede usar el método waitForLocation para esperar a que la ubicación sea un valor dado:
$browser->waitForLocation('/secret');
El método waitForLocation también puede usarse para esperar a que la ubicación actual de la ventana sea una URL completamente calificada:
$browser->waitForLocation('https://example.com/path');
También puede esperar la ubicación de una ruta nombrada:
$browser->waitForRoute($routeName, $parameters);
#Esperar recargas de página
Si necesita esperar a que una página se recargue después de realizar una acción, use el método waitForReload:
use Laravel\Dusk\Browser;
$browser->waitForReload(function (Browser $browser) {
$browser->press('Submit');
})
->assertSee('Success!');
Dado que la necesidad de esperar a que la página se recargue suele ocurrir después de hacer clic en un botón, puede usar el método clickAndWaitForReload para mayor comodidad:
$browser->clickAndWaitForReload('.selector')
->assertSee('something');
#Esperar expresiones JavaScript
A veces puede desear pausar la ejecución de una prueba hasta que una expresión JavaScript dada evalúe a true. Puede lograr esto fácilmente usando el método waitUntil. Al pasar una expresión a este método, no necesita incluir la palabra clave return ni un punto y coma al final:
// Esperar un máximo de cinco segundos para que la expresión sea verdadera...
$browser->waitUntil('App.data.servers.length > 0');
// Esperar un máximo de un segundo para que la expresión sea verdadera...
$browser->waitUntil('App.data.servers.length > 0', 1);
#Esperar expresiones Vue
Los métodos waitUntilVue y waitUntilVueIsNot pueden usarse para esperar hasta que un atributo de un componente Vue tenga un valor dado:
// Esperar hasta que el atributo del componente contenga el valor dado...
$browser->waitUntilVue('user.name', 'Taylor', '@user');
// Esperar hasta que el atributo del componente no contenga el valor dado...
$browser->waitUntilVueIsNot('user.name', null, '@user');
#Esperar eventos JavaScript
El método waitForEvent puede usarse para pausar la ejecución de una prueba hasta que ocurra un evento JavaScript:
$browser->waitForEvent('load');
El listener del evento se adjunta al alcance actual, que por defecto es el elemento body. Al usar un selector con alcance, el listener se adjuntará al elemento que coincida:
$browser->with('iframe', function (Browser $iframe) {
// Esperar el evento load del iframe...
$iframe->waitForEvent('load');
});
También puede proporcionar un selector como segundo argumento al método waitForEvent para adjuntar el listener a un elemento específico:
$browser->waitForEvent('load', '.selector');
También puede esperar eventos en los objetos document y window:
// Esperar hasta que el documento sea desplazado...
$browser->waitForEvent('scroll', 'document');
// Esperar un máximo de cinco segundos hasta que la ventana sea redimensionada...
$browser->waitForEvent('resize', 'window', 5);
#Esperar con un callback
Muchos de los métodos de "espera" en Dusk dependen del método subyacente waitUsing. Puede usar este método directamente para esperar a que un closure dado retorne true. El método waitUsing acepta el número máximo de segundos para esperar, el intervalo en el que se debe evaluar el closure, el closure y un mensaje de error opcional:
$browser->waitUsing(10, 1, function () use ($something) {
return $something->isReady();
}, "Something wasn't ready in time.");
#Desplazar un elemento a la vista
A veces puede no poder hacer clic en un elemento porque está fuera del área visible del navegador. El método scrollIntoView desplazará la ventana del navegador hasta que el elemento en el selector dado esté dentro de la vista:
$browser->scrollIntoView('.selector')
->click('.selector');
#Aserciones disponibles
Dusk proporciona una variedad de aserciones que puede hacer contra su aplicación. Todas las aserciones disponibles están documentadas en la lista a continuación:
<style> .collection-method-list > p { columns: 10.8em 3; -moz-columns: 10.8em 3; -webkit-columns: 10.8em 3; } .collection-method-list a { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } </style>assertTitle assertTitleContains assertUrlIs assertSchemeIs assertSchemeIsNot assertHostIs assertHostIsNot assertPortIs assertPortIsNot assertPathBeginsWith 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
Afirmar que el título de la página coincide con el texto dado:
$browser->assertTitle($title);
#assertTitleContains
Afirmar que el título de la página contiene el texto dado:
$browser->assertTitleContains($title);
#assertUrlIs
Afirmar que la URL actual (sin la cadena de consulta) coincide con la cadena dada:
$browser->assertUrlIs($url);
#assertSchemeIs
Afirmar que el esquema de la URL actual coincide con el esquema dado:
$browser->assertSchemeIs($scheme);
#assertSchemeIsNot
Afirmar que el esquema de la URL actual no coincide con el esquema dado:
$browser->assertSchemeIsNot($scheme);
#assertHostIs
Afirmar que el host de la URL actual coincide con el host dado:
$browser->assertHostIs($host);
#assertHostIsNot
Afirmar que el host de la URL actual no coincide con el host dado:
$browser->assertHostIsNot($host);
#assertPortIs
Afirmar que el puerto de la URL actual coincide con el puerto dado:
$browser->assertPortIs($port);
#assertPortIsNot
Afirmar que el puerto de la URL actual no coincide con el puerto dado:
$browser->assertPortIsNot($port);
#assertPathBeginsWith
Afirmar que la ruta de la URL actual comienza con la ruta dada:
$browser->assertPathBeginsWith('/home');
#assertPathIs
Afirmar que la ruta actual coincide con la ruta dada:
$browser->assertPathIs('/home');
#assertPathIsNot
Afirmar que la ruta actual no coincide con la ruta dada:
$browser->assertPathIsNot('/home');
#assertRouteIs
Afirmar que la URL actual coincide con la URL de una ruta nombrada:
$browser->assertRouteIs($name, $parameters);
#assertQueryStringHas
Afirmar que el parámetro dado de la cadena de consulta está presente:
$browser->assertQueryStringHas($name);
Afirmar que el parámetro dado de la cadena de consulta está presente y tiene un valor dado:
$browser->assertQueryStringHas($name, $value);
#assertQueryStringMissing
Afirmar que el parámetro dado de la cadena de consulta está ausente:
$browser->assertQueryStringMissing($name);
#assertFragmentIs
Afirmar que el fragmento hash actual de la URL coincide con el fragmento dado:
$browser->assertFragmentIs('anchor');
#assertFragmentBeginsWith
Afirmar que el fragmento hash actual de la URL comienza con el fragmento dado:
$browser->assertFragmentBeginsWith('anchor');
#assertFragmentIsNot
Afirmar que el fragmento hash actual de la URL no coincide con el fragmento dado:
$browser->assertFragmentIsNot('anchor');
#assertHasCookie
Afirmar que la cookie cifrada dada está presente:
$browser->assertHasCookie($name);
#assertHasPlainCookie
Afirmar que la cookie sin cifrar dada está presente:
$browser->assertHasPlainCookie($name);
#assertCookieMissing
Afirmar que la cookie cifrada dada no está presente:
$browser->assertCookieMissing($name);
#assertPlainCookieMissing
Afirmar que la cookie sin cifrar dada no está presente:
$browser->assertPlainCookieMissing($name);
#assertCookieValue
Afirmar que una cookie cifrada tiene un valor dado:
$browser->assertCookieValue($name, $value);
#assertPlainCookieValue
Asegura que una cookie sin cifrar tenga un valor dado:
$browser->assertPlainCookieValue($name, $value);
#assertSee
Asegura que el texto dado esté presente en la página:
$browser->assertSee($text);
#assertDontSee
Asegura que el texto dado no esté presente en la página:
$browser->assertDontSee($text);
#assertSeeIn
Asegura que el texto dado esté presente dentro del selector:
$browser->assertSeeIn($selector, $text);
#assertDontSeeIn
Asegura que el texto dado no esté presente dentro del selector:
$browser->assertDontSeeIn($selector, $text);
#assertSeeAnythingIn
Asegura que cualquier texto esté presente dentro del selector:
$browser->assertSeeAnythingIn($selector);
#assertSeeNothingIn
Asegura que no haya texto presente dentro del selector:
$browser->assertSeeNothingIn($selector);
#assertScript
Asegura que la expresión JavaScript dada se evalúe al valor dado:
$browser->assertScript('window.isLoaded')
->assertScript('document.readyState', 'complete');
#assertSourceHas
Asegura que el código fuente dado esté presente en la página:
$browser->assertSourceHas($code);
#assertSourceMissing
Asegura que el código fuente dado no esté presente en la página:
$browser->assertSourceMissing($code);
#assertSeeLink
Asegura que el enlace dado esté presente en la página:
$browser->assertSeeLink($linkText);
#assertDontSeeLink
Asegura que el enlace dado no esté presente en la página:
$browser->assertDontSeeLink($linkText);
#assertInputValue
Asegura que el campo de entrada dado tenga el valor dado:
$browser->assertInputValue($field, $value);
#assertInputValueIsNot
Asegura que el campo de entrada dado no tenga el valor dado:
$browser->assertInputValueIsNot($field, $value);
#assertChecked
Asegura que la casilla de verificación dada esté marcada:
$browser->assertChecked($field);
#assertNotChecked
Asegura que la casilla de verificación dada no esté marcada:
$browser->assertNotChecked($field);
#assertIndeterminate
Asegura que la casilla de verificación dada esté en un estado indeterminado:
$browser->assertIndeterminate($field);
#assertRadioSelected
Asegura que el campo de radio dado esté seleccionado:
$browser->assertRadioSelected($field, $value);
#assertRadioNotSelected
Asegura que el campo de radio dado no esté seleccionado:
$browser->assertRadioNotSelected($field, $value);
#assertSelected
Asegura que el dropdown dado tenga el valor dado seleccionado:
$browser->assertSelected($field, $value);
#assertNotSelected
Asegura que el dropdown dado no tenga el valor dado seleccionado:
$browser->assertNotSelected($field, $value);
#assertSelectHasOptions
Asegura que el array dado de valores esté disponible para ser seleccionado:
$browser->assertSelectHasOptions($field, $values);
#assertSelectMissingOptions
Asegura que el array dado de valores no esté disponible para ser seleccionado:
$browser->assertSelectMissingOptions($field, $values);
#assertSelectHasOption
Asegura que el valor dado esté disponible para ser seleccionado en el campo dado:
$browser->assertSelectHasOption($field, $value);
#assertSelectMissingOption
Asegura que el valor dado no esté disponible para ser seleccionado:
$browser->assertSelectMissingOption($field, $value);
#assertValue
Asegura que el elemento que coincide con el selector dado tenga el valor dado:
$browser->assertValue($selector, $value);
#assertValueIsNot
Asegura que el elemento que coincide con el selector dado no tenga el valor dado:
$browser->assertValueIsNot($selector, $value);
#assertAttribute
Asegura que el elemento que coincide con el selector dado tenga el valor dado en el atributo proporcionado:
$browser->assertAttribute($selector, $attribute, $value);
#assertAttributeContains
Asegura que el elemento que coincide con el selector dado contenga el valor dado en el atributo proporcionado:
$browser->assertAttributeContains($selector, $attribute, $value);
#assertAttributeDoesntContain
Asegura que el elemento que coincide con el selector dado no contenga el valor dado en el atributo proporcionado:
$browser->assertAttributeDoesntContain($selector, $attribute, $value);
#assertAriaAttribute
Asegura que el elemento que coincide con el selector dado tenga el valor dado en el atributo aria proporcionado:
$browser->assertAriaAttribute($selector, $attribute, $value);
Por ejemplo, dado el marcado <button aria-label="Add"></button>, puede asegurarse contra el atributo aria-label así:
$browser->assertAriaAttribute('button', 'label', 'Add')
#assertDataAttribute
Asegura que el elemento que coincide con el selector dado tenga el valor dado en el atributo data proporcionado:
$browser->assertDataAttribute($selector, $attribute, $value);
Por ejemplo, dado el marcado <tr id="row-1" data-content="attendees"></tr>, puede asegurarse contra el atributo data-label así:
$browser->assertDataAttribute('#row-1', 'content', 'attendees')
#assertVisible
Asegura que el elemento que coincide con el selector dado sea visible:
$browser->assertVisible($selector);
#assertPresent
Asegura que el elemento que coincide con el selector dado esté presente en el código fuente:
$browser->assertPresent($selector);
#assertNotPresent
Asegura que el elemento que coincide con el selector dado no esté presente en el código fuente:
$browser->assertNotPresent($selector);
#assertMissing
Asegura que el elemento que coincide con el selector dado no sea visible:
$browser->assertMissing($selector);
#assertInputPresent
Asegura que un input con el nombre dado esté presente:
$browser->assertInputPresent($name);
#assertInputMissing
Asegura que un input con el nombre dado no esté presente en el código fuente:
$browser->assertInputMissing($name);
#assertDialogOpened
Asegura que un diálogo JavaScript con el mensaje dado haya sido abierto:
$browser->assertDialogOpened($message);
#assertEnabled
Asegura que el campo dado esté habilitado:
$browser->assertEnabled($field);
#assertDisabled
Asegura que el campo dado esté deshabilitado:
$browser->assertDisabled($field);
#assertButtonEnabled
Asegura que el botón dado esté habilitado:
$browser->assertButtonEnabled($button);
#assertButtonDisabled
Asegura que el botón dado esté deshabilitado:
$browser->assertButtonDisabled($button);
#assertFocused
Asegura que el campo dado esté enfocado:
$browser->assertFocused($field);
#assertNotFocused
Asegura que el campo dado no esté enfocado:
$browser->assertNotFocused($field);
#assertAuthenticated
Asegura que el usuario esté autenticado:
$browser->assertAuthenticated();
#assertGuest
Asegura que el usuario no esté autenticado:
$browser->assertGuest();
#assertAuthenticatedAs
Asegura que el usuario esté autenticado como el usuario dado:
$browser->assertAuthenticatedAs($user);
#assertVue
Dusk incluso permite hacer aserciones sobre el estado de los datos de un componente Vue. Por ejemplo, imagine que su aplicación contiene el siguiente componente Vue:
// HTML...
<profile dusk="profile-component"></profile>
// Definición del componente...
Vue.component('profile', {
template: '<div>{{ user.name }}</div>',
data: function () {
return {
user: {
name: 'Taylor'
}
};
}
});
Puede hacer aserciones sobre el estado del componente Vue así:
/**
* Un ejemplo básico de prueba Vue.
*/
public function test_vue(): void
{
$this->browse(function (Browser $browser) {
$browser->visit('/')
->assertVue('user.name', 'Taylor', '@profile-component');
});
}
#assertVueIsNot
Asegura que una propiedad de datos de un componente Vue dado no coincida con el valor dado:
$browser->assertVueIsNot($property, $value, $componentSelector = null);
#assertVueContains
Asegura que una propiedad de datos de un componente Vue dado sea un array y contenga el valor dado:
$browser->assertVueContains($property, $value, $componentSelector = null);
#assertVueDoesntContain
Asegura que una propiedad de datos de un componente Vue dado sea un array y no contenga el valor dado:
$browser->assertVueDoesntContain($property, $value, $componentSelector = null);
#Pages
A veces, las pruebas requieren realizar varias acciones complicadas en secuencia. Esto puede hacer que sus pruebas sean más difíciles de leer y entender. Las Pages de Dusk le permiten definir acciones expresivas que luego pueden ejecutarse en una página dada mediante un solo método. Las Pages también permiten definir atajos para selectores comunes de su aplicación o de una sola página.
#Generación de páginas
Para generar un objeto page, ejecute el comando Artisan dusk:page. Todos los objetos page se colocarán en el directorio tests/Browser/Pages de su aplicación:
php artisan dusk:page Login
#Configuración de páginas
Por defecto, las pages tienen tres métodos: url, assert y elements. Ahora discutiremos los métodos url y assert. El método elements será discutido con más detalle abajo.
#El método url
El método url debe devolver la ruta de la URL que representa la página. Dusk usará esta URL al navegar a la página en el navegador:
/**
* Obtener la URL para la página.
*/
public function url(): string
{
return '/login';
}
#El método assert
El método assert puede hacer cualquier aserción necesaria para verificar que el navegador esté realmente en la página dada. No es estrictamente necesario colocar algo dentro de este método; sin embargo, puede hacer estas aserciones si lo desea. Estas aserciones se ejecutarán automáticamente al navegar a la página:
/**
* Asegurar que el navegador esté en la página.
*/
public function assert(Browser $browser): void
{
$browser->assertPathIs($this->url());
}
#Navegación a páginas
Una vez que se ha definido una page, puede navegar a ella usando el método visit:
use Tests\Browser\Pages\Login;
$browser->visit(new Login);
A veces ya puede estar en una página dada y necesitar "cargar" los selectores y métodos de la página en el contexto actual de la prueba. Esto es común al presionar un botón y ser redirigido a una página dada sin navegar explícitamente a ella. En esta situación, puede usar el método on para cargar la página:
use Tests\Browser\Pages\CreatePlaylist;
$browser->visit('/dashboard')
->clickLink('Create Playlist')
->on(new CreatePlaylist)
->assertSee('@create');
#Selectores abreviados
El método elements dentro de las clases page le permite definir atajos rápidos y fáciles de recordar para cualquier selector CSS en su página. Por ejemplo, definamos un atajo para el campo de entrada "email" de la página de login de la aplicación:
/**
* Obtener los atajos de elementos para la página.
*
* @return array<string, string>
*/
public function elements(): array
{
return [
'@email' => 'input[name=email]',
];
}
Una vez definido el atajo, puede usar el selector abreviado en cualquier lugar donde normalmente usaría un selector CSS completo:
$browser->type('@email', 'taylor@laravel.com');
#Selectores abreviados globales
Después de instalar Dusk, una clase base Page se colocará en su directorio tests/Browser/Pages. Esta clase contiene un método siteElements que puede usarse para definir selectores abreviados globales que deberían estar disponibles en todas las páginas de su aplicación:
/**
* Obtener los atajos globales de elementos para el sitio.
*
* @return array<string, string>
*/
public static function siteElements(): array
{
return [
'@element' => '#selector',
];
}
#Métodos de páginas
Además de los métodos predeterminados definidos en las pages, puede definir métodos adicionales que pueden usarse en todas sus pruebas. Por ejemplo, imaginemos que estamos construyendo una aplicación de gestión musical. Una acción común para una página de la aplicación podría ser crear una playlist. En lugar de reescribir la lógica para crear una playlist en cada prueba, puede definir un método createPlaylist en una clase page:
<?php
namespace Tests\Browser\Pages;
use Laravel\Dusk\Browser;
class Dashboard extends Page
{
// Otros métodos de la página...
/**
* Crear una nueva playlist.
*/
public function createPlaylist(Browser $browser, string $name): void
{
$browser->type('name', $name)
->check('share')
->press('Create Playlist');
}
}
Una vez definido el método, puede usarlo en cualquier prueba que utilice la page. La instancia del navegador se pasará automáticamente como el primer argumento a los métodos personalizados de la page:
use Tests\Browser\Pages\Dashboard;
$browser->visit(new Dashboard)
->createPlaylist('My Playlist')
->assertSee('My Playlist');
#Components
Los componentes son similares a los “objetos page” de Dusk, pero están destinados a piezas de UI y funcionalidad que se reutilizan en toda su aplicación, como una barra de navegación o una ventana de notificaciones. Por lo tanto, los componentes no están ligados a URLs específicas.
#Generación de componentes
Para generar un componente, ejecute el comando Artisan dusk:component. Los nuevos componentes se colocan en el directorio tests/Browser/Components:
php artisan dusk:component DatePicker
Como se muestra arriba, un "selector de fecha" es un ejemplo de componente que podría existir en toda su aplicación en varias páginas. Puede volverse tedioso escribir manualmente la lógica de automatización del navegador para seleccionar una fecha en docenas de pruebas en su suite. En cambio, podemos definir un componente Dusk para representar el selector de fecha, permitiéndonos encapsular esa lógica dentro del componente:
<?php
namespace Tests\Browser\Components;
use Laravel\Dusk\Browser;
use Laravel\Dusk\Component as BaseComponent;
class DatePicker extends BaseComponent
{
/**
* Obtener el selector raíz para el componente.
*/
public function selector(): string
{
return '.date-picker';
}
/**
* Asegurar que la página del navegador contenga el componente.
*/
public function assert(Browser $browser): void
{
$browser->assertVisible($this->selector());
}
/**
* Obtener los atajos de elementos para el 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',
];
}
/**
* Seleccionar la fecha dada.
*/
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);
});
}
}
#Uso de componentes
Una vez definido el componente, podemos seleccionar fácilmente una fecha dentro del selector de fecha desde cualquier prueba. Y, si la lógica necesaria para seleccionar una fecha cambia, solo necesitamos actualizar el componente:
<?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
{
/**
* Un ejemplo básico de prueba de componente.
*/
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');
});
}
}
#Integración continua
La mayoría de las configuraciones de integración continua de Dusk esperan que su aplicación Laravel se sirva usando el servidor de desarrollo PHP incorporado en el puerto 8000. Por lo tanto, antes de continuar, debe asegurarse de que su entorno de integración continua tenga una variable de entorno APP_URL con el valor http://127.0.0.1:8000.
#Heroku CI
Para ejecutar pruebas Dusk en Heroku CI, agregue el siguiente buildpack de Google Chrome y scripts a su archivo app.json de Heroku:
{
"environments": {
"test": {
"buildpacks": [
{ "url": "heroku/php" },
{ "url": "https://github.com/heroku/heroku-buildpack-google-chrome" }
],
"scripts": {
"test-setup": "cp .env.testing .env",
"test": "nohup bash -c './vendor/laravel/dusk/bin/chromedriver-linux > /dev/null 2>&1 &' && nohup bash -c 'php artisan serve --no-reload > /dev/null 2>&1 &' && php artisan dusk"
}
}
}
}
#Travis CI
Para ejecutar sus pruebas Dusk en Travis CI, use la siguiente configuración .travis.yml. Dado que Travis CI no es un entorno gráfico, necesitaremos tomar algunos pasos adicionales para lanzar un navegador Chrome. Además, usaremos php artisan serve para lanzar el servidor web incorporado de PHP:
language: php
php:
- 7.3
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
Si usa GitHub Actions para ejecutar sus pruebas Dusk, puede usar el siguiente archivo de configuración como punto de partida. Al igual que TravisCI, usaremos el comando php artisan serve para lanzar el servidor web incorporado de 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: Prepare The Environment
run: cp .env.example .env
- name: Create Database
run: |
sudo systemctl start mysql
mysql --user="root" --password="root" -e "CREATE DATABASE \`my-database\` character set UTF8mb4 collate utf8mb4_bin;"
- name: Install Composer Dependencies
run: composer install --no-progress --prefer-dist --optimize-autoloader
- name: Generate Application Key
run: php artisan key:generate
- name: Upgrade Chrome Driver
run: php artisan dusk:chrome-driver --detect
- name: Start Chrome Driver
run: ./vendor/laravel/dusk/bin/chromedriver-linux &
- name: Run Laravel Server
run: php artisan serve --no-reload &
- name: Run Dusk Tests
run: php artisan dusk
- name: Upload Screenshots
if: failure()
uses: actions/upload-artifact@v2
with:
name: screenshots
path: tests/Browser/screenshots
- name: Upload Console Logs
if: failure()
uses: actions/upload-artifact@v2
with:
name: console
path: tests/Browser/console
#Chipper CI
Si usa Chipper CI para ejecutar sus pruebas Dusk, puede usar el siguiente archivo de configuración como punto de partida. Usaremos el servidor incorporado de PHP para ejecutar Laravel y así poder escuchar las solicitudes:
# archivo .chipperci.yml
version: 1
environment:
php: 8.2
node: 16
# Incluir Chrome en el entorno de construcción
services:
- dusk
# Construir todos los 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
# Crear un archivo env para dusk, asegurando que APP_URL use 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
Para aprender más sobre cómo ejecutar pruebas Dusk en Chipper CI, incluyendo cómo usar bases de datos, consulte la documentación oficial de Chipper CI.