Documentación de Laravel 10.x
Aquí encontrarás fragmentos de código de Laravel y consejos útiles sobre desarrollo web.
Laravel Dusk proporciona una API de automatización de navegadores y pruebas expresiva y fácil de usar. Por defecto, Dusk no requiere que instales JDK o Selenium en tu computadora local. En su lugar, Dusk utiliza una instalación independiente de ChromeDriver. Sin embargo, eres libre de utilizar cualquier otro controlador compatible con Selenium que prefieras.
Para empezar, debes instalar Google Chrome y agregar la dependencia de Composer laravel/dusk
a tu proyecto:
composer require --dev laravel/dusk
Advertencia Si estás registrando manualmente el proveedor de servicios de Dusk, nunca lo registres en tu entorno de producción, ya que esto podría permitir que usuarios arbitrarios autentiquen con tu aplicación.
Después de instalar el paquete Dusk, ejecuta el comando php artisan dusk:install
. Este comando creará un directorio tests/Browser
, un ejemplo de prueba Dusk e instalará el binario de Chrome Driver para tu sistema operativo:
php artisan dusk:install
A continuación, establece la variable de entorno APP_URL
en el archivo .env
de tu aplicación. Este valor debe coincidir con la URL que utilizas para acceder a tu aplicación en un navegador.
Nota Si estás utilizando Laravel Sail para gestionar tu entorno de desarrollo local, consulta también la documentación de Sail sobre configurar y ejecutar pruebas Dusk.
Si deseas instalar una versión diferente de ChromeDriver a la instalada por Laravel Dusk a través del comando dusk:install
, puedes usar el comando dusk:chrome-driver
:
# Install the latest version of ChromeDriver for your OS...php artisan dusk:chrome-driver # Install a given version of ChromeDriver for your OS...php artisan dusk:chrome-driver 86 # Install a given version of ChromeDriver for all supported OSs...php artisan dusk:chrome-driver --all # Install the version of ChromeDriver that matches the detected version of Chrome / Chromium for your OS...php artisan dusk:chrome-driver --detect
Advertencia Dusk requiere que los binarios de
chromedriver
sean ejecutables. Si tienes problemas para ejecutar Dusk, asegúrate de que los binarios sean ejecutables con el siguiente comando:chmod -R 0755 vendor/laravel/dusk/bin/
.
Por defecto, Dusk utiliza Google Chrome y una instalación independiente de ChromeDriver para ejecutar tus pruebas de navegador. Sin embargo, puedes iniciar tu propio servidor Selenium y ejecutar tus pruebas contra cualquier navegador que desees.
Para comenzar, abre tu archivo tests/DuskTestCase.php
, que es el caso base de prueba Dusk para tu aplicación. Dentro de este archivo, puedes eliminar la llamada al método startChromeDriver
. Esto evitará que Dusk inicie automáticamente el ChromeDriver:
/** * Preparar para la ejecución de la prueba Dusk. * * @beforeClass */public static function prepare(): void{ // static::startChromeDriver();}
A continuación, puedes modificar el método driver
para conectarte a la URL y puerto de tu elección. Además, puedes modificar las "capacidades deseadas" que se deben pasar al WebDriver:
use Facebook\WebDriver\Remote\RemoteWebDriver; /** * Crea la instancia de RemoteWebDriver. */protected function driver(): RemoteWebDriver{ return RemoteWebDriver::create( 'http://localhost:4444/wd/hub', DesiredCapabilities::phantomjs() );}
Para generar una prueba Dusk, utiliza el comando Artisan dusk:make
. La prueba generada se ubicará en el directorio tests/Browser
:
php artisan dusk:make LoginTest
La mayoría de las pruebas que escribas interactuarán con páginas que recuperan datos de la base de datos de tu aplicación; sin embargo, tus pruebas Dusk nunca deben usar el rasgo RefreshDatabase
. El rasgo RefreshDatabase
utiliza transacciones de base de datos que no serán aplicables ni estarán disponibles en las solicitudes HTTP. En su lugar, tienes dos opciones: el rasgo DatabaseMigrations
y el rasgo DatabaseTruncation
.
El rasgo DatabaseMigrations
ejecutará tus migraciones de base de datos antes de cada prueba. Sin embargo, eliminar y volver a crear las tablas de tu 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;}
Advertencia Las bases de datos en memoria de SQLite no se pueden utilizar al ejecutar pruebas de Dusk. Dado que el navegador se ejecuta dentro de su propio proceso, no podrá acceder a las bases de datos en memoria de otros procesos.
Antes de usar el rasgo DatabaseTruncation
, debes instalar el paquete doctrine/dbal
mediante el administrador de paquetes Composer:
composer require --dev doctrine/dbal
El rasgo DatabaseTruncation
migrará tu base de datos en la primera prueba para asegurarse de que las tablas de tu base de datos se hayan creado correctamente. Sin embargo, en pruebas posteriores, las tablas de la base de datos simplemente se truncarán, proporcionando un impulso de velocidad sobre volver a ejecutar todas tus migraciones de base de datos:
<?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 rasgo truncará todas las tablas excepto la tabla migrations
. Si deseas personalizar las tablas que se deben truncar, puedes definir una propiedad $tablesToTruncate
en tu clase de prueba:
/** * Indica qué tablas deben ser truncadas. * * @var array */protected $tablesToTruncate = ['users'];
Alternativamente, puedes definir una propiedad $exceptTables
en tu clase de prueba para especificar qué tablas deben excluirse de la truncación:
/** * Indica qué tablas deben ser excluidas de la truncación. * * @var array */protected $exceptTables = ['users'];
Para especificar las conexiones de base de datos que deben tener sus tablas truncadas, puedes definir una propiedad $connectionsToTruncate
en tu clase de prueba:
/** * Indica qué conexiones deben tener sus tablas truncadas. * * @var array */protected $connectionsToTruncate = ['mysql'];
Si deseas ejecutar código antes o después de que se realice la truncación de la base de datos, puedes definir los métodos beforeTruncatingDatabase
o afterTruncatingDatabase
en tu clase de prueba:
/** * Realiza cualquier trabajo que deba llevarse a cabo antes de que la base de datos comience a truncarse. */protected function beforeTruncatingDatabase(): void{ //} /** * Realiza cualquier trabajo que deba llevarse a cabo después de que la base de datos haya terminado de truncarse. */protected function afterTruncatingDatabase(): void{ //}
Para ejecutar tus pruebas de navegador, ejecuta el comando Artisan dusk
:
php artisan dusk
Si tuviste fallas en las pruebas la última vez que ejecutaste el comando dusk
, puedes ahorrar tiempo volviendo a ejecutar primero las pruebas fallidas usando el comando dusk:fails
:
php artisan dusk:fails
El comando dusk
acepta cualquier argumento que normalmente acepta el ejecutor de pruebas PHPUnit, como permitirte ejecutar solo las pruebas de un grupo dado:
php artisan dusk --group=foo
Nota Si estás utilizando Laravel Sail para gestionar tu entorno de desarrollo local, consulta la documentación de Sail sobre configurar y ejecutar pruebas Dusk.
Por defecto, Dusk intentará iniciar automáticamente ChromeDriver. Si esto no funciona para tu sistema en particular, puedes iniciar manualmente ChromeDriver antes de ejecutar el comando dusk
. Si eliges iniciar ChromeDriver manualmente, debes comentar la siguiente línea de tu archivo tests/DuskTestCase.php
:
/** * Preparar para la ejecución de la prueba Dusk. * * @beforeClass */public static function prepare(): void{ // static::startChromeDriver();}
Además, si inicias ChromeDriver en un puerto que no sea 9515, debes modificar el método driver
de la misma clase para reflejar el puerto correcto:
use Facebook\WebDriver\Remote\RemoteWebDriver; /** * Crea la instancia de RemoteWebDriver. */protected function driver(): RemoteWebDriver{ return RemoteWebDriver::create( 'http://localhost:9515', DesiredCapabilities::chrome() );}
Para forzar a Dusk a usar su propio archivo de entorno al ejecutar pruebas, crea un archivo .env.dusk.{entorno}
en la raíz de tu proyecto. Por ejemplo, si vas a iniciar el comando dusk
desde tu entorno local
, debes crear un archivo .env.dusk.local
.
Cuando se ejecutan las pruebas, Dusk realizará una copia de seguridad de tu archivo .env
y renombrará tu entorno de Dusk a .env
. Una vez que las pruebas hayan terminado, tu archivo .env
se restaurará.
Para empezar, 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 "Iniciar sesión". Para crear una instancia del navegador, puedes llamar al método browse
desde dentro de tu 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 del navegador. */ public function test_basic_example(): void { $user = User::factory()->create([ ]); $this->browse(function (Browser $browser) use ($user) { $browser->visit('/login') ->type('email', $user->email) ->type('password', 'password') ->press('Login') ->assertPathIs('/home'); }); }}
Como puedes ver en el ejemplo anterior, el método browse
acepta un cierre. Dusk pasará automáticamente una instancia del navegador a este cierre y es el objeto principal utilizado para interactuar y hacer afirmaciones contra tu aplicación.
A veces, es posible que necesites varios navegadores para llevar a cabo una prueba correctamente. Por ejemplo, puede ser necesario utilizar varios navegadores para probar una pantalla de chat que interactúa con websockets. Para crear varios navegadores, simplemente agrega más argumentos de navegador a la firma del cierre dado 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');});
El método visit
se puede utilizar para navegar a una URI dada dentro de tu aplicación:
$browser->visit('/login');
Puedes usar el método visitRoute
para navegar a una ruta con nombre:
$browser->visitRoute('login');
Puedes navegar hacia atrás y hacia adelante utilizando los métodos back
y forward
:
$browser->back(); $browser->forward();
Puedes usar el método refresh
para actualizar la página:
$browser->refresh();
Puedes usar el método resize
para ajustar el tamaño de la ventana del navegador:
$browser->resize(1920, 1080);
El método maximize
se puede utilizar 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 redimensionará automáticamente el navegador para que se ajuste al contenido antes de tomar una captura de pantalla. Puedes deshabilitar esta función llamando al método disableFitOnFailure
dentro de tu prueba:
$browser->disableFitOnFailure();
Puedes usar el método move
para mover la ventana del navegador a una posición diferente en tu pantalla:
$browser->move($x = 100, $y = 100);
Si deseas definir un método de navegador personalizado que puedas reutilizar en varias de tus pruebas, puedes usar el método macro
en la clase Browser
. Normalmente, debes llamar a este método desde el método boot
de un proveedor de servicios:
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider;use Laravel\Dusk\Browser; class DuskServiceProvider extends ServiceProvider{ /** * Registra 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 su primer argumento y un cierre como su segundo. El cierre de la macro se ejecutará al llamar a la macro como un 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');});
A menudo, estarás probando páginas que requieren autenticación. Puedes usar el método loginAs
de Dusk para evitar interactuar con la pantalla de inicio de sesión de tu aplicación durante cada prueba. El método loginAs
acepta una clave primaria asociada con tu modelo autenticable o una instancia de modelo autenticable:
use App\Models\User;use Laravel\Dusk\Browser; $this->browse(function (Browser $browser) { $browser->loginAs(User::find(1)) ->visit('/home');});
Advertencia Después de usar el método
loginAs
, la sesión de usuario se mantendrá para todas las pruebas dentro del archivo.
Puedes 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');
Puedes usar el método plainCookie
para obtener o establecer el valor de una cookie no cifrada:
$browser->plainCookie('name'); $browser->plainCookie('name', 'Taylor');
Puedes usar el método deleteCookie
para eliminar la cookie dada:
$browser->deleteCookie('name');
Puedes usar el método script
para ejecutar declaraciones de JavaScript arbitrarias 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');
Puedes usar el método screenshot
para tomar una captura de pantalla y almacenarla con el nombre de archivo dado. Todas las capturas de pantalla se almacenarán en el directorio tests/Browser/screenshots
:
$browser->screenshot('filename');
El método responsiveScreenshots
se puede utilizar para tomar una serie de capturas de pantalla en varios puntos de interrupción:
$browser->responsiveScreenshots('filename');
Puedes usar el método storeConsoleLog
para escribir la salida actual de la consola del navegador en disco con el nombre de archivo proporcionado. La salida de la consola se almacenará en el directorio tests/Browser/console
:
$browser->storeConsoleLog('filename');
Puedes usar el método storeSource
para escribir el origen actual de la página en disco con el nombre de archivo proporcionado. El origen de la página se almacenará en el directorio tests/Browser/source
:
$browser->storeSource('filename');
Elegir buenos selectores CSS para interactuar con elementos es una de las partes más difíciles de escribir pruebas Dusk. Con el tiempo, los cambios en el frontend pueden hacer que selectores CSS como los siguientes rompan tus pruebas:
// HTML... <button>Login</button> // Prueba... $browser->click('.login-page .container div > button');
Los selectores Dusk te permiten centrarte en escribir pruebas efectivas en lugar de recordar selectores CSS. Para definir un selector, agrega un atributo dusk
a tu elemento HTML. Luego, al interactuar con un navegador Dusk, agrega el prefijo @
al selector para manipular el elemento adjunto dentro de tu prueba:
// HTML... <button dusk="login-button">Login</button> // Prueba... $browser->click('@login-button');
Si lo deseas, puedes personalizar el atributo HTML que utiliza el selector Dusk mediante el método selectorHtmlAttribute
. Normalmente, este método debería llamarse desde el método boot
del AppServiceProvider
de tu aplicación:
use Laravel\Dusk\Dusk; Dusk::selectorHtmlAttribute('data-dusk');
Dusk proporciona varios métodos para interactuar con el valor actual, el texto de visualización 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, usa el método value
:
// Recupera el valor...$value = $browser->value('selector'); // Establece el valor...$browser->value('selector', 'value');
Puedes usar el método inputValue
para obtener el "valor" de un elemento de entrada que tiene un nombre de campo dado:
$value = $browser->inputValue('field');
El método text
se puede usar para recuperar el texto de visualización de un elemento que coincide con el selector dado:
$text = $browser->text('selector');
Finalmente, el método attribute
se puede usar para recuperar el valor de un atributo de un elemento que coincide con el selector dado:
$attribute = $browser->attribute('selector', 'value');
Dusk proporciona una variedad de métodos para interactuar con formularios y elementos de entrada. Primero, echemos un vistazo a un ejemplo de cómo escribir texto en un campo de entrada:
Observa que, aunque el método acepta uno si es necesario, no estamos obligados a pasar un selector CSS completo 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, puedes usar el método append
:
$browser->type('tags', 'foo') ->append('tags', ', bar, baz');
Puedes borrar el valor de una entrada usando el método clear
:
$browser->clear('email');
Puedes indicarle a Dusk que escriba lentamente usando el método typeSlowly
. Por defecto, Dusk esperará 100 milisegundos entre pulsaciones de teclas. Para personalizar la cantidad de tiempo entre pulsaciones de teclas, puedes pasar el número adecuado de milisegundos como tercer argumento al método:
$browser->typeSlowly('mobile', '+1 (202) 555-5555'); $browser->typeSlowly('mobile', '+1 (202) 555-5555', 300);
Puedes usar el método appendSlowly
para agregar texto lentamente:
$browser->type('tags', 'foo') ->appendSlowly('tags', ', bar, baz');
Para seleccionar un valor disponible en un elemento select
, puedes 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
, debes pasar el valor de opción subyacente en lugar del texto de visualización:
$browser->select('size', 'Large');
Puedes seleccionar una opción aleatoria omitiendo el segundo argumento:
$browser->select('size');
Al proporcionar una matriz como segundo argumento al método select
, puedes indicarle al método que seleccione varias opciones:
$browser->select('categories', ['Art', 'Music']);
Para "marcar" una casilla de verificación, puedes usar el método check
. Al igual que muchos otros métodos relacionados con la entrada, no se requiere un selector CSS completo. Si no se puede encontrar una coincidencia de selector CSS, Dusk buscará una casilla de verificación con un atributo name
coincidente:
$browser->check('terms');
Se puede utilizar el método uncheck
para "desmarcar" una casilla de verificación:
$browser->uncheck('terms');
Para "seleccionar" una opción de entrada radio
, puedes usar el método radio
. Al igual que muchos otros métodos relacionados con la entrada, no se requiere un selector CSS completo. Si no se puede encontrar una coincidencia de selector CSS, Dusk buscará una entrada radio
con atributos name
y value
coincidentes:
$browser->radio('size', 'large');
El método attach
se puede utilizar para adjuntar un archivo a un elemento de entrada de tipo file
. Al igual que muchos otros métodos relacionados con la entrada, no se requiere un selector CSS completo. Si no se puede encontrar una coincidencia de selector CSS, Dusk buscará una entrada file
con un atributo name
coincidente:
$browser->attach('photo', __DIR__.'/photos/mountains.png');
Advertencia La función
attach
requiere que la extensión PHPZip
esté instalada y habilitada en tu servidor.
El método press
se puede utilizar para hacer clic en un elemento de botón en la página. El argumento dado al método press
puede ser tanto el texto de visualización del botón como un selector CSS / Dusk:
$browser->press('Login');
Al enviar formularios, muchas aplicaciones desactivan el botón de envío del formulario después de presionarlo y luego vuelven a habilitar el botón cuando se completa la solicitud HTTP del envío del formulario. Para presionar un botón y esperar a que se vuelva a habilitar, puedes usar el método pressAndWaitFor
:
// Presiona el botón y espera un máximo de 5 segundos para que esté habilitado...$browser->pressAndWaitFor('Save'); // Presiona el botón y espera un máximo de 1 segundo para que esté habilitado...$browser->pressAndWaitFor('Save', 1);
Para hacer clic en un enlace, puedes usar el método clickLink
en la instancia del navegador. El método clickLink
hará clic en el enlace que tiene el texto de visualización dado:
$browser->clickLink($linkText);
Puedes usar el método seeLink
para determinar si hay un enlace con el texto de visualización dado visible en la página:
if ($browser->seeLink($linkText)) { // ...}
Advertencia Estos métodos interactúan con jQuery. Si jQuery no está disponible en la página, Dusk lo inyectará automáticamente en la página para que esté disponible durante la duración de la prueba.
El método keys
te permite proporcionar secuencias de entrada más complejas a un elemento dado de lo que normalmente permite el método type
. Por ejemplo, puedes indicarle a Dusk que mantenga presionadas las teclas modificadoras al ingresar valores. En este ejemplo, se mantendrá presionada la tecla shift
mientras se ingresa taylor
en el elemento que coincide con el selector dado. Después de escribir taylor
, se escribirá swift
sin ninguna tecla modificadoras:
$browser->keys('selector', ['{shift}', 'taylor'], 'swift');
Otro caso de uso valioso para el método keys
es enviar una combinación de "teclas de acceso directo" al selector CSS principal de tu aplicación:
$browser->keys('.app', ['{command}', 'j']);
Nota Todas las teclas modificadoras como
{command}
están envueltas en{}
caracteres y coinciden con las constantes definidas en la claseFacebook\WebDriver\WebDriverKeys
, que se pueden encontrar en GitHub.
Dusk también proporciona un método withKeyboard
, que te permite realizar interacciones avanzadas con el teclado de forma fluida a través de la clase Laravel\Dusk\Keyboard
. La clase Keyboard
proporciona 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']);});
Si deseas definir interacciones de teclado personalizadas que puedas reutilizar fácilmente en tu conjunto de pruebas, puedes usar el método macro
proporcionado por la clase Keyboard
. Normalmente, deberías llamar a este método desde el método boot
de un proveedor de servicios:
<?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 las macros del navegador 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 su primer argumento y un cierre como su segundo. El cierre 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());
El método click
se puede utilizar para hacer clic en un elemento que coincide con el selector CSS o Dusk dado:
$browser->click('.selector');
El método clickAtXPath
se puede utilizar para hacer clic en un elemento que coincida con la expresión XPath proporcionada:
$browser->clickAtXPath('//div[@class = "selector"]');
El método clickAtPoint
se puede utilizar para hacer clic en el elemento más superior en un par de coordenadas dadas en relación con el área visible del navegador:
$browser->clickAtPoint($x = 0, $y = 0);
El método doubleClick
se puede utilizar para simular el doble clic de un ratón:
$browser->doubleClick();
El método rightClick
se puede utilizar para simular el clic derecho de un ratón:
$browser->rightClick(); $browser->rightClick('.selector');
El método clickAndHold
se puede utilizar para simular el clic y mantenimiento de un botón del ratón. Una llamada subsiguiente al método releaseMouse
deshará este comportamiento y liberará el botón del ratón:
$browser->clickAndHold() ->pause(1000) ->releaseMouse();
El método controlClick
se puede utilizar para simular el evento ctrl+click
dentro del navegador:
$browser->controlClick();
El método mouseover
se puede utilizar cuando necesitas mover el ratón sobre un elemento que coincida con el selector CSS o Dusk dado:
$browser->mouseover('.selector');
El método drag
se puede utilizar para arrastrar un elemento que coincida con el selector a otro elemento:
$browser->drag('.from-selector', '.to-selector');
O puedes 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, puedes arrastrar un elemento por un desplazamiento dado:
$browser->dragOffset('.selector', $x = 10, $y = 10);
Dusk proporciona varios métodos para interactuar con los cuadros de diálogo de JavaScript. Por ejemplo, puedes usar el método waitForDialog
para esperar a que aparezca un cuadro de diálogo de JavaScript. Este método acepta un argumento opcional que indica cuántos segundos esperar a que aparezca el cuadro de diálogo:
$browser->waitForDialog($seconds = null);
El método assertDialogOpened
se puede utilizar para afirmar que se ha mostrado un cuadro de diálogo y contiene el mensaje dado:
$browser->assertDialogOpened('Dialog message');
Si el cuadro de diálogo de JavaScript contiene una solicitud, puedes usar el método typeInDialog
para escribir un valor en la solicitud:
$browser->typeInDialog('Hello World');
Para cerrar un cuadro de diálogo de JavaScript abierto haciendo clic en el botón "OK", puedes invocar el método acceptDialog
:
$browser->acceptDialog();
Para cerrar un cuadro de diálogo de JavaScript abierto haciendo clic en el botón "Cancelar", puedes invocar el método dismissDialog
:
$browser->dismissDialog();
Si necesitas interactuar con elementos dentro de un iframe, puedes usar el método withinFrame
. Todas las interacciones con elementos que tienen lugar dentro del cierre 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');});
A veces, es posible que desees realizar varias operaciones al limitar todas las operaciones dentro de un selector dado. Por ejemplo, es posible que desees afirmar que un texto existe solo dentro de una tabla y luego hacer clic en un botón dentro de esa tabla. Puedes usar el método with
para lograr esto. Todas las operaciones realizadas dentro del cierre proporcionado al método with
estarán limitadas al selector original:
$browser->with('.table', function (Browser $table) { $table->assertSee('Hello World') ->clickLink('Delete');});
Ocasionalmente, es posible que necesites ejecutar afirmaciones fuera del alcance actual. Puedes 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'); });});
Al probar aplicaciones que utilizan 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. Utilizando varios métodos, puedes esperar a que los elementos sean visibles en la página o incluso esperar hasta que se evalúe a true
una expresión JavaScript dada.
Si solo necesitas pausar la prueba durante un número dado de milisegundos, utiliza el método pause
:
$browser->pause(1000);
Si necesitas pausar la prueba solo si una condición dada es true
, utiliza el método pauseIf
:
$browser->pauseIf(App::environment('production'), 1000);
De manera similar, si necesitas pausar la prueba a menos que una condición dada sea true
, puedes usar el método pauseUnless
:
$browser->pauseUnless(App::environment('testing'), 1000);
El método waitFor
se puede utilizar para pausar la ejecución de la prueba hasta que se muestre en la página el elemento que coincida con el selector CSS o Dusk dado. De forma predeterminada, esto pausará la prueba durante un máximo de cinco segundos antes de lanzar una excepción. Si es necesario, puedes pasar un umbral de tiempo personalizado como segundo argumento al método:
// Espera un máximo de cinco segundos para el selector...$browser->waitFor('.selector'); // Espera un máximo de un segundo para el selector...$browser->waitFor('.selector', 1);
También puedes esperar hasta que el elemento que coincida con el selector dado contenga el texto dado:
// Espera un máximo de cinco segundos para que el selector contenga el texto dado...$browser->waitForTextIn('.selector', 'Hello World'); // Espera un máximo de un segundo para que el selector contenga el texto dado...$browser->waitForTextIn('.selector', 'Hello World', 1);
También puedes esperar hasta que el elemento que coincida con el selector dado falte en la página:
// Espera un máximo de cinco segundos hasta que el selector falte...$browser->waitUntilMissing('.selector'); // Espera un máximo de un segundo hasta que el selector falte...$browser->waitUntilMissing('.selector', 1);
O puedes esperar hasta que el elemento que coincida con el selector dado esté habilitado o deshabilitado:
// Espera un máximo de cinco segundos hasta que el selector esté habilitado...$browser->waitUntilEnabled('.selector'); // Espera un máximo de un segundo hasta que el selector esté habilitado...$browser->waitUntilEnabled('.selector', 1); // Espera un máximo de cinco segundos hasta que el selector esté deshabilitado...$browser->waitUntilDisabled('.selector'); // Espera un máximo de un segundo hasta que el selector esté deshabilitado...$browser->waitUntilDisabled('.selector', 1);
Ocasionalmente, es posible que desees esperar a que aparezca un elemento que coincida con un selector dado y luego interactuar con el elemento. Por ejemplo, es posible que desees esperar hasta que esté disponible una ventana modal y luego hacer clic en el botón "OK" dentro de la ventana modal. El método whenAvailable
se puede utilizar para lograr esto. Todas las operaciones de elementos realizadas dentro del cierre dado estarán limitadas al selector original:
$browser->whenAvailable('.modal', function (Browser $modal) { $modal->assertSee('Hello World') ->press('OK');});
El método waitForText
se puede utilizar para esperar hasta que se muestre en la página el texto dado:
// Espera un máximo de cinco segundos para el texto...$browser->waitForText('Hello World'); // Espera un máximo de un segundo para el texto...$browser->waitForText('Hello World', 1);
Puedes usar el método waitUntilMissingText
para esperar hasta que el texto mostrado se haya eliminado de la página:
// Espera un máximo de cinco segundos para que el texto sea eliminado...$browser->waitUntilMissingText('Hello World'); // Espera un máximo de un segundo para que el texto sea eliminado...$browser->waitUntilMissingText('Hello World', 1);
El método waitForLink
se puede utilizar para esperar hasta que el texto del enlace dado se muestre en la página:
// Espera un máximo de cinco segundos para el enlace...$browser->waitForLink('Create'); // Espera un máximo de un segundo para el enlace...$browser->waitForLink('Create', 1);
El método waitForInput
se puede utilizar para esperar hasta que el campo de entrada dado sea visible en la página:
// Espera un máximo de cinco segundos para el input...$browser->waitForInput($field); // Espera un máximo de un segundo para el input...$browser->waitForInput($field, 1);
Al realizar 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. Puedes 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 se puede usar para esperar a que la ubicación actual de la ventana sea una URL completamente calificada:
$browser->waitForLocation('https://example.com/path');
También puedes esperar a la ubicación de una ruta con nombre:
$browser->waitForRoute($routeName, $parameters);
Si necesitas esperar a que se recargue una página después de realizar una acción, usa 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 se recargue la página suele ocurrir después de hacer clic en un botón, puedes usar el método clickAndWaitForReload
por conveniencia:
$browser->clickAndWaitForReload('.selector') ->assertSee('something');
A veces, es posible que desees pausar la ejecución de una prueba hasta que una expresión JavaScript dada se evalúe como true
. Puedes lograrlo fácilmente usando el método waitUntil
. Al pasar una expresión a este método, no es necesario incluir la palabra clave return
ni un punto y coma al final:
// Espera un máximo de cinco segundos a que la expresión sea verdadera...$browser->waitUntil('App.data.servers.length > 0'); // Espera un máximo de un segundo a que la expresión sea verdadera...$browser->waitUntil('App.data.servers.length > 0', 1);
Los métodos waitUntilVue
y waitUntilVueIsNot
se pueden usar para esperar hasta que un atributo de un componente Vue tenga un valor dado:
// Espera hasta que el atributo del componente contenga el valor dado...$browser->waitUntilVue('user.name', 'Taylor', '@user'); // Espera hasta que el atributo del componente no contenga el valor dado...$browser->waitUntilVueIsNot('user.name', null, '@user');
El método waitForEvent
se puede usar para pausar la ejecución de una prueba hasta que ocurra un evento JavaScript:
$browser->waitForEvent('load');
El escucha de eventos está adjunto al alcance actual, que es el elemento body
por defecto. Al usar un selector con alcance, el escucha de eventos se adjuntará al elemento coincidente:
$browser->with('iframe', function (Browser $iframe) { // Espera el evento de carga del iframe... $iframe->waitForEvent('load');});
También puedes proporcionar un selector como segundo argumento al método waitForEvent
para adjuntar el escucha de eventos a un elemento específico:
$browser->waitForEvent('load', '.selector');
También puedes esperar eventos en los objetos document
y window
:
// Espera hasta que se haga scroll en el documento...$browser->waitForEvent('scroll', 'document'); // Espera un máximo de cinco segundos hasta que la ventana cambie de tamaño...$browser->waitForEvent('resize', 'window', 5);
Muchos de los métodos de "espera" en Dusk dependen del método subyacente waitUsing
. Puedes usar este método directamente para esperar a que un cierre dado devuelva true
. El método waitUsing
acepta el número máximo de segundos para esperar, el intervalo en el que se debe evaluar el cierre, el cierre y un mensaje de error opcional:
$browser->waitUsing(10, 1, function () use ($something) { return $something->isReady();}, "Something wasn't ready in time.");
A veces, es posible que no puedas 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');
Dusk proporciona una variedad de afirmaciones que puedes hacer contra tu aplicación. Todas las afirmaciones disponibles se documentan en la siguiente lista:
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 assertAriaAttribute assertDataAttribute assertVisible assertPresent assertNotPresent assertMissing assertInputPresent assertInputMissing assertDialogOpened assertEnabled assertDisabled assertButtonEnabled assertButtonDisabled assertFocused assertNotFocused assertAuthenticated assertGuest assertAuthenticatedAs assertVue assertVueIsNot assertVueContains assertVueDoesNotContain
Asegura que el título de la página coincida con el texto dado:
$browser->assertTitle($title);
Asegura que el título de la página contenga el texto dado:
$browser->assertTitleContains($title);
Asegura que la URL actual (sin la cadena de consulta) coincida con la cadena dada:
$browser->assertUrlIs($url);
Asegura que el esquema de la URL actual coincida con el esquema dado:
$browser->assertSchemeIs($scheme);
Asegura que el esquema de la URL actual no coincida con el esquema dado:
$browser->assertSchemeIsNot($scheme);
Asegura que el host de la URL actual coincida con el host dado:
$browser->assertHostIs($host);
Asegura que el host de la URL actual no coincida con el host dado:
$browser->assertHostIsNot($host);
Asegura que el puerto de la URL actual coincida con el puerto dado:
$browser->assertPortIs($port);
Asegura que el puerto de la URL actual no coincida con el puerto dado:
$browser->assertPortIsNot($port);
Asegura que la ruta de la URL actual comience con la ruta dada:
$browser->assertPathBeginsWith('/home');
Asegura que la ruta actual coincida con la ruta dada:
$browser->assertPathIs('/home');
Asegura que la ruta actual no coincida con la ruta dada:
$browser->assertPathIsNot('/home');
Asegura que la URL actual coincida con la URL de la ruta con nombre dada:
$browser->assertRouteIs($name, $parameters);
Asegura que el parámetro de cadena de consulta dado esté presente:
$browser->assertQueryStringHas($name);
Asegura que el parámetro de cadena de consulta dado esté presente y tenga un valor dado:
$browser->assertQueryStringHas($name, $value);
Asegura que el parámetro de cadena de consulta dado esté ausente:
$browser->assertQueryStringMissing($name);
Asegura que el fragmento hash actual de la URL coincida con el fragmento dado:
$browser->assertFragmentIs('anchor');
Asegura que el fragmento hash actual de la URL comience con el fragmento dado:
$browser->assertFragmentBeginsWith('anchor');
Asegura que el fragmento hash actual de la URL no coincida con el fragmento dado:
$browser->assertFragmentIsNot('anchor');
Asegura que la cookie cifrada dada esté presente:
$browser->assertHasCookie($name);
Asegura que la cookie no cifrada dada esté presente:
$browser->assertHasPlainCookie($name);
Asegura que la cookie cifrada dada no esté presente:
$browser->assertCookieMissing($name);
Asegura que la cookie no cifrada dada no esté presente:
$browser->assertPlainCookieMissing($name);
Asegura que una cookie cifrada tenga un valor dado:
$browser->assertCookieValue($name, $value);
Asegura que una cookie no cifrada tenga un valor dado:
$browser->assertPlainCookieValue($name, $value);
Asegura que el texto dado esté presente en la página:
$browser->assertSee($text);
Asegura que el texto dado no esté presente en la página:
$browser->assertDontSee($text);
Asegura que el texto dado esté presente dentro del selector:
$browser->assertSeeIn($selector, $text);
Asegura que el texto dado no esté presente dentro del selector:
$browser->assertDontSeeIn($selector, $text);
Asegura que hay algún texto presente dentro del selector:
$browser->assertSeeAnythingIn($selector);
Asegura que no hay texto presente dentro del selector:
$browser->assertSeeNothingIn($selector);
Asegura que la expresión JavaScript dada se evalúa como el valor dado:
$browser->assertScript('window.isLoaded') ->assertScript('document.readyState', 'complete');
Asegura que el código fuente dado esté presente en la página:
$browser->assertSourceHas($code);
Asegura que el código fuente dado no esté presente en la página:
$browser->assertSourceMissing($code);
Asegura que el enlace dado esté presente en la página:
$browser->assertSeeLink($linkText);
Asegura que el enlace dado no esté presente en la página:
$browser->assertDontSeeLink($linkText);
Asegura que el campo de entrada dado tenga el valor dado:
$browser->assertInputValue($field, $value);
Asegura que el campo de entrada dado no tenga el valor dado:
$browser->assertInputValueIsNot($field, $value);
Asegura que la casilla de verificación dada esté marcada:
$browser->assertChecked($field);
Asegura que la casilla de verificación dada no esté marcada:
$browser->assertNotChecked($field);
Asegura que la casilla de verificación dada esté en un estado indeterminado:
$browser->assertIndeterminate($field);
Asegura que el campo de opción de radio dado esté seleccionado:
$browser->assertRadioSelected($field, $value);
Asegura que el campo de opción de radio dado no esté seleccionado:
$browser->assertRadioNotSelected($field, $value);
Asegura que la lista desplegable dada tenga el valor dado seleccionado:
$browser->assertSelected($field, $value);
Asegura que la lista desplegable dada no tenga el valor dado seleccionado:
$browser->assertNotSelected($field, $value);
Asegura que la lista de valores dada esté disponible para ser seleccionada:
$browser->assertSelectHasOptions($field, $values);
Asegura que la lista de valores dada no esté disponible para ser seleccionada:
$browser->assertSelectMissingOptions($field, $values);
Asegura que el valor dado esté disponible para ser seleccionado en el campo dado:
$browser->assertSelectHasOption($field, $value);
Asegura que el valor dado no esté disponible para ser seleccionado:
$browser->assertSelectMissingOption($field, $value);
Asegura que el elemento que coincide con el selector dado tenga el valor dado:
$browser->assertValue($selector, $value);
Asegura que el elemento que coincide con el selector dado no tenga el valor dado:
$browser->assertValueIsNot($selector, $value);
Asegura que el elemento que coincide con el selector dado tenga el valor dado en el atributo proporcionado:
$browser->assertAttribute($selector, $attribute, $value);
Asegura que el elemento que coincide con el selector dado contenga el valor dado en el atributo proporcionado:
$browser->assertAttributeContains($selector, $attribute, $value);
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=\"Añadir\"></button>
, puedes afirmar contra el atributo aria-label
así:
$browser->assertAriaAttribute('button', 'label', 'Add')
Asegura que el elemento que coincide con el selector dado tenga el valor dado en el atributo de datos proporcionado:
$browser->assertDataAttribute($selector, $attribute, $value);
Por ejemplo, dado el marcado <tr id=\"fila-1\" data-content=\"asistentes\"></tr>
, puedes afirmar contra el atributo data-label
así:
$browser->assertDataAttribute('#row-1', 'content', 'attendees')
Asegura que el elemento que coincide con el selector dado sea visible:
$browser->assertVisible($selector);
Asegura que el elemento que coincide con el selector dado esté presente en el origen:
$browser->assertPresent($selector);
Asegura que el elemento que coincide con el selector dado no esté presente en el origen:
$browser->assertNotPresent($selector);
Asegura que el elemento que coincide con el selector dado no sea visible:
$browser->assertMissing($selector);
Asegura que un campo con el nombre dado esté presente:
$browser->assertInputPresent($name);
Asegura que un campo con el nombre dado no esté presente en el origen:
$browser->assertInputMissing($name);
Asegura que se haya abierto un cuadro de diálogo de JavaScript con el mensaje dado:
$browser->assertDialogOpened($message);
Asegura que el campo dado esté habilitado:
$browser->assertEnabled($field);
Asegura que el campo dado esté deshabilitado:
$browser->assertDisabled($field);
Asegura que el botón dado esté habilitado:
$browser->assertButtonEnabled($button);
Asegura que el botón dado esté deshabilitado:
$browser->assertButtonDisabled($button);
Asegura que el campo dado esté enfocado:
$browser->assertFocused($field);
Asegura que el campo dado no esté enfocado:
$browser->assertNotFocused($field);
Asegura que el usuario esté autenticado:
$browser->assertAuthenticated();
Asegura que el usuario no esté autenticado:
$browser->assertGuest();
Asegura que el usuario esté autenticado como el usuario dado:
$browser->assertAuthenticatedAs($user);
Dusk incluso te permite hacer afirmaciones sobre el estado de los datos de componentes Vue. Por ejemplo, imagina que tu 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' } }; }});
Puedes afirmar sobre el estado del componente Vue de la siguiente manera:
/** * 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'); });}
Asegura que una propiedad de datos dada del componente Vue no coincida con el valor dado:
$browser->assertVueIsNot($property, $value, $componentSelector = null);
Asegura que una propiedad de datos dada de un componente Vue sea un array y contenga el valor proporcionado:
$browser->assertVueContains($property, $value, $componentSelector = null);
Asegura que una propiedad de datos dada del componente Vue sea una matriz y no contenga el valor dado:
$browser->assertVueDoesNotContain($property, $value, $componentSelector = null);
A veces, las pruebas requieren que se realicen varias acciones complicadas en secuencia. Esto puede hacer que tus pruebas sean más difíciles de leer y entender. Las páginas de Dusk te permiten definir acciones expresivas que luego se pueden realizar en una página dada a través de un solo método. Las páginas también te permiten definir accesos directos a selectores comunes para tu aplicación o para una sola página.
Para generar un objeto de página, ejecuta el comando Artisan dusk:page
. Todos los objetos de página se colocarán en el directorio tests/Browser/Pages
de tu aplicación:
php artisan dusk:page Login
Por defecto, las páginas tienen tres métodos: url
, assert
, y elements
. Discutiremos los métodos url
y assert
ahora. El método elements
se discutirá con más detalle a continuación.
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:
/** * Obtiene la URL de la página. */public function url(): string{ return '/login';}
assert
El método assert
puede realizar cualquier afirmación necesaria para verificar que el navegador esté realmente en la página dada. En realidad, no es necesario colocar nada dentro de este método; sin embargo, eres libre de hacer estas afirmaciones si lo deseas. Estas afirmaciones se ejecutarán automáticamente al navegar a la página:
/** * Asegura que el navegador esté en la página. */public function assert(Browser $browser): void{ $browser->assertPathIs($this->url());}
Una vez que se haya definido una página, puedes navegar a ella usando el método visit
:
use Tests\Browser\Pages\Login; $browser->visit(new Login);
A veces ya puedes estar en una página dada y necesitar "cargar" los selectores y métodos de la página en el contexto de la prueba actual. Esto es común cuando presionas un botón y te redirigen a una página dada sin navegar explícitamente a ella. En esta situación, puedes 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');
El método elements
dentro de las clases de página te permite definir accesos directos rápidos y fáciles de recordar para cualquier selector CSS en tu página. Por ejemplo, definamos un acceso directo para el campo de entrada "correo electrónico" de la página de inicio de sesión de la aplicación:
/** * Obtiene los atajos de elementos para la página. * * @return array<string, string> */public function elements(): array{ return [ '@email' => 'input[name=email]', ];}
Una vez que se haya definido el acceso directo, puedes usar el selector abreviado en cualquier lugar donde normalmente usarías un selector CSS completo:
Después de instalar Dusk, se colocará una clase base Page
en tu directorio tests/Browser/Pages
. Esta clase contiene un método siteElements
que se puede utilizar para definir accesos directos globales que deberían estar disponibles en cada página de tu aplicación:
/** * Obtiene los atajos de elementos globales para el sitio. * * @return array<string, string> */public static function siteElements(): array{ return [ '@element' => '#selector', ];}
Además de los métodos predeterminados definidos en las páginas, puedes definir métodos adicionales que se pueden utilizar en tus pruebas. Por ejemplo, imaginemos que estás construyendo una aplicación de gestión de música. Una acción común para una página de la aplicación podría ser crear una lista de reproducción. En lugar de volver a escribir la lógica para crear una lista de reproducción en cada prueba, puedes definir un método createPlaylist
en una clase de página:
<?php namespace Tests\Browser\Pages; use Laravel\Dusk\Browser; class Dashboard extends Page{ // Otros métodos de la página... /** * Crea una nueva lista de reproducción. */ public function createPlaylist(Browser $browser, string $name): void { $browser->type('name', $name) ->check('share') ->press('Create Playlist'); }}
Una vez que se haya definido el método, puedes usarlo en cualquier prueba que utilice la página. La instancia del navegador se pasará automáticamente como el primer argumento a los métodos personalizados de la página:
use Tests\Browser\Pages\Dashboard; $browser->visit(new Dashboard) ->createPlaylist('My Playlist') ->assertSee('My Playlist');
Los componentes son similares a los "objetos de página" de Dusk, pero están destinados a piezas de interfaz de usuario y funcionalidades que se reutilizan en toda tu aplicación, como una barra de navegación o una ventana de notificación. Como tal, los componentes no están vinculados a URL específicas.
Para generar un componente, ejecuta 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 un componente que podría existir en toda tu aplicación en una variedad de páginas. Puede resultar engorroso escribir manualmente la lógica de automatización del navegador para seleccionar una fecha en docenas de pruebas en toda tu suite de pruebas. En su lugar, podemos definir un componente de Dusk para representar el selector de fecha, lo que nos permite 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{ /** * Obtiene el selector raíz para el componente. */ public function selector(): string { return '.date-picker'; } /** * Asegura que la página del navegador contenga el componente. */ public function assert(Browser $browser): void { $browser->assertVisible($this->selector()); } /** * Obtiene 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', ]; } /** * Selecciona 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); }); }}
Una vez que se haya 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'); }); }}
Advertencia La mayoría de las configuraciones de integración continua de Dusk esperan que tu aplicación Laravel se sirva utilizando el servidor de desarrollo PHP incorporado en el puerto 8000. Por lo tanto, antes de continuar, asegúrate de que tu entorno de integración continua tenga un valor de variable de entorno
APP_URL
dehttp://127.0.0.1:8000
.
Para ejecutar pruebas Dusk en Heroku CI, agrega el siguiente buildpack de Google Chrome y scripts a tu 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" } } }}
Para ejecutar tus pruebas Dusk en Travis CI, utiliza la siguiente configuración de .travis.yml
. Dado que Travis CI no es un entorno gráfico, deberemos tomar algunos pasos adicionales para lanzar un navegador Chrome. Además, utilizaremos php artisan serve
para iniciar 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
Si estás utilizando GitHub Actions para ejecutar tus pruebas Dusk, puedes usar el siguiente archivo de configuración como punto de partida. Al igual que TravisCI, utilizaremos el comando php artisan serve
para iniciar el servidor web incorporado de PHP:
name: CIon: [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
Si estás utilizando Chipper CI para ejecutar tus pruebas Dusk, puedes usar el siguiente archivo de configuración como punto de partida. Utilizaremos el servidor incorporado de PHP para ejecutar Laravel y escuchar las solicitudes:
# file .chipperci.ymlversion: 1 environment: php: 8.2 node: 16 # Include Chrome in the build environmentservices: - dusk # Build all commitson: 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
Para obtener más información sobre cómo ejecutar pruebas Dusk en Chipper CI, incluido el uso de bases de datos, consulta la documentación oficial de Chipper CI.