Estamos actualizando el sitio. Durante unos días es posible que veas fallos de diseño o de traducción. La documentación sigue disponible: si una página se ve mal, recárgala más tarde.

Inicio Laravel 10.x Laravel Dusk

Laravel Dusk

10.x 7 de mar. de 2026

#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');
});

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');

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);

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);

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

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);

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);

#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());
}

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.