- Introducción
- Instalación
- Primeros pasos
- Interactuando con elementos
- Aserciones disponibles
- Páginas
- Componentes
- Integración continua
Introducción
Laravel Dusk proporciona una API de automatización y prueba para navegador expresiva y fácil de usar. De forma predeterminada, Dusk no requiere que instales JDK o Selenium en tu computador. En su lugar, Dusk usa una instalación de ChromeDriver independiente. Sin embargo, siéntete libre de utilizar cualquier otro driver compatible con Selenium que desees.
Instalación
Para empezar, debes agregar la dependencia de Composer laravel/dusk
a tu proyecto:
composer require --dev laravel/dusk
Si estás registrando manualmente el proveedor de servicio de Dusk, nunca deberías registrarlo en tu entorno de producción, ya que hacerlo así podría conducir a que usuarios arbitrarios sean capaces de autenticarse en tu aplicación.
Después de la instalación del paquete Dusk, ejecuta el comando Artisan dusk:install
:
php artisan dusk:install
Un directorio Browser
será creado dentro de tu directorio tests
y contendrá una prueba de ejemplo. Seguido, establece la variable de entorno APP_URL
en tu archivo .env
. Este valor debería coincidir con la URL que uses para acceder a tu aplicación en un navegador.
Para ejecutar tus pruebas, usa el comando de Artisan dusk
. El comando dusk
acepta cualquier argumento que también sea aceptado por el comando phpunit
:
php artisan dusk
Si tuviste fallos en las pruebas la última vez que se ejecutó el comando dusk
, puedes ahorrar tiempo volviendo a ejecutar las pruebas fallidas usando el comando dusk:fails
:
php artisan dusk:fails
Administrando las instalaciones de ChromeDriver
Si te gustaría instalar una versión diferente de ChromeDriver a la incluida con Laravel Dusk, 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 74 # Install a given version of ChromeDriver for all supported OSs... php artisan dusk:chrome-driver --all
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/
.
Usando otros navegadores
De forma predeterminada, Dusk usa Google Chrome y una instalación de ChromeDriver independiente para ejecutar tus pruebas de navegador. Sin embargo, puedes iniciar tu propio servidor Selenium y ejecutar tus pruebas en cualquier navegador que desees.
Para empezar, abre tu archivo tests/DuskTestCase.php
, el cual es el caso de prueba de Dusk básico para tu aplicación. Dentro de este archivo, puedes remover la ejecución del método startChromeDriver
. Esto evitará que Dusk inicie automáticamente ChromeDriver:
/** * Prepare for Dusk test execution. * * @beforeClass * @return void */ public static function prepare() { // static::startChromeDriver(); }
Luego de esto, puedes modificar el método driver
para conectar a la URL y puerto de tu preferencia. Además, puedes modificar las «capacidades deseadas» que deberían ser pasadas al WebDriver:
/** * Create the RemoteWebDriver instance. * * @return \Facebook\WebDriver\Remote\RemoteWebDriver */ protected function driver() { return RemoteWebDriver::create( 'http://localhost:4444/wd/hub', DesiredCapabilities::phantomjs() ); }
Primeros pasos
Generando pruebas
Para generar una prueba de Dusk, usa el comando de Artisan dusk:make
. La prueba generada será colocada en el directorio tests/Browser
:
php artisan dusk:make LoginTest
Ejecutando pruebas
Para ejecutar tus pruebas de navegador, usa el comando Artisan dusk
:
php artisan dusk
Si tuviste fallos en las pruebas la última vez que se ejecutó el comando dusk
, puedes ahorrar tiempo volviendo a ejecutar las pruebas fallidas usando el comando dusk:fails
:
php artisan dusk:fails
El comando dusk
acepta cualquier argumento que sea aceptado normalmente por el administrador de pruebas de PHPUnit, permitiendo que ejecutes solamente las pruebas para un grupo dado, etc:
php artisan dusk --group=foo
Iniciando manualmente ChromeDriver
De forma predeterminada, Dusk intentará automáticamente iniciar ChromeDriver. Si esto no funciona para tu sistema en particular, puedes iniciar manualmente ChromeDriver antes de ejecutar el comando dusk
. Si eliges iniciar manualmente ChromeDriver, debes comentar la siguiente línea de tu archivo tests/DuskTestCase.php
:
/** * Prepare for Dusk test execution. * * @beforeClass * @return void */ public static function prepare() { // static::startChromeDriver(); }
Además, si inicias ChromeDriver en un puerto diferente a 9515, deberías modificar el método driver
de la misma clase:
/** * Create the RemoteWebDriver instance. * * @return \Facebook\WebDriver\Remote\RemoteWebDriver */ protected function driver() { return RemoteWebDriver::create( 'http://localhost:9515', DesiredCapabilities::chrome() ); }
Manejo de entorno
Para forzar que Dusk use su propio archivo de entorno al momento de ejecutar las pruebas, crea un archivo .env.dusk.{environment}
en el directorio raíz de tu proyecto. Por ejemplo, si estás iniciando el comando dusk
desde tu entorno local
, deberías crear un archivo .env.dusk.local
.
Al momento de ejecutar pruebas, Dusk respaldará tu archivo .env
y renombrará tu entorno Dusk a .env
. Una vez que las pruebas han sido completadas, tu archivo .env
será restaurado.
Creando navegadores
Para empezar, vamos a escribir una prueba que verifica que podemos entrar a nuestra aplicación. Después de generar una prueba, podemos modificarla para visitar la página de login, introducir algunas credenciales y presionar el botón «Login». Para crear una instancia del navegador, ejecuta el método browse
:
<?php namespace Tests\Browser; use App\User; use Illuminate\Foundation\Testing\DatabaseMigrations; use Laravel\Dusk\Chrome; use Tests\DuskTestCase; class ExampleTest extends DuskTestCase { use DatabaseMigrations; /** * A basic browser test example. * * @return void */ public function testBasicExample() { $user = factory(User::class)->create([ 'email' => '[email protected]', ]); $this->browse(function ($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 una función callback. Una instancia de navegador será pasada automáticamente a esta función de retorno (callback) por Dusk y es el objeto principal utilizado para interactuar y hacer aserciones en la aplicación.
Creando múltiples navegadores
Algunas veces puedes necesitar múltiples navegadores con el propósito de ejecutar apropiadamente una prueba. Por ejemplo, múltiples navegadores pueden ser necesitados para probar una pantalla de conversaciones que interactúa con websockets. Para crear múltiples navegadores, «solicita» más de un navegador en la firma del callback dado al método browse
:
$this->browse(function ($first, $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'); });
Redimensionando las ventanas del navegador
Puedes usar el método resize
para ajustar el tamaño de la ventana del navegador:
$browser->resize(1920, 1080);
El método maximize
puede ser usado para maximizar la ventana del navegador:
$browser->maximize();
El método fitContent
redimensionará la ventana del navegador para que coincida con el tamaño del contenido:
$browser->fitContent();
Cuando una prueba falla, Dusk redimensionará automáticamente el navegador para ajustar al contenido previo a la toma de una captura de pantalla. Puedes desactivar esta característica ejecutando el método disableFitOnFailure
dentro de tu prueba:
$browser->disableFitOnFailure();
Macros de navegador
Si desea definir un método de navegador personalizado que puedas reutilizar en una variedad de tus pruebas, puedes usar el método macro
en la clase Browser
. Normalmente, deberías llamar a este método desde el método boot
del proveedor de servicios:
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use Laravel\Dusk\Browser; class DuskServiceProvider extends ServiceProvider { /** * Register the Dusk's browser macros. * * @return void */ public function boot() { Browser::macro('scrollToElement', function ($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 del macro se ejecutará cuando se llame al macro como un método en una implementación de Browser
:
$this->browse(function ($browser) use ($user) { $browser->visit('/pay') ->scrollToElement('#credit-card-details') ->assertSee('Enter Credit Card Details'); });
Autenticación
Frecuentemente, estarás probando páginas que requieren autenticación. Puedes usar el método loginAs
de Dusk con el propósito de evitar interactuar con la pantalla de login durante cada prueba. El método loginAs
acepta un ID de usuario o una instancia de modelo de usuario:
$this->browse(function ($first, $second) { $first->loginAs(User::find(1)) ->visit('/home'); });
Después de usar el método loginAs
, la sesión de usuario será mantenida para todas las pruebas dentro del archivo.
Migraciones de bases de datos
Cuando tu prueba requiera migraciones, como el ejemplo de autenticación visto antes, nunca deberías usar el trait RefreshDatabase
. El trait RefreshDatabase
se apoya en transacciones de base de datos, las cuales no serán aplicables a través de las solicitudes HTTP. En su lugar, usa el trait DatabaseMigrations
:
<?php namespace Tests\Browser; use App\User; use Illuminate\Foundation\Testing\DatabaseMigrations; use Laravel\Dusk\Chrome; use Tests\DuskTestCase; class ExampleTest extends DuskTestCase { use DatabaseMigrations; }
Interactuando con elementos
Selectores de Dusk
Elegir buenos selectores CSS para interactuar con elementos es una de las partes más difíciles de escribir las pruebas de Dusk. Con el tiempo, los cambios del diseño frontend pueden causar que los selectores CSS como los siguientes dañen tus pruebas:
// HTML... <button>Login</button> // Test... $browser->click('.login-page .container div > button');
Los selectores de Dusk permiten que te enfoques en la escritura de pruebas efectivas en vez de recordar selectores CSS. Para definir un selector, agrega un atributo dusk
a tu elemento HTML. Después, agrega un prefijo al selector con @
para manipular el elemento conectado dentro de una prueba de Dusk:
// HTML... <button dusk="login-button">Login</button> // Test... $browser->click('@login-button');
Haciendo clic en enlaces
Para hacer clic sobre 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 dado en la pantalla:
$browser->clickLink($linkText);
Este método interactúa con jQuery. Si jQuery no está disponible en la página, Dusk lo inyectará automáticamente de modo que esté disponible por la duración de la prueba.
Texto, Valores y Atributos
Obteniendo y estableciendo valores
Dusk proporciona varios métodos para interactuar con el texto de pantalla, valor y atributos de elementos en la página actual. Por ejemplo, para obtener el «valor» de un elemento que coincida con un selector dado, usa el método value
:
// Retrieve the value... $value = $browser->value('selector'); // Set the value... $browser->value('selector', 'value');
Obteniendo texto
El método text
puede ser usado para obtener el texto de pantalla de un elemento que coincida con el selector dado:
$text = $browser->text('selector');
Obteniendo atributos
Finalmente, el método attribute
puede ser usado para obtener un atributo de un elemento que coincida con el selector dado:
$attribute = $browser->attribute('selector', 'value');
Usando Formularios
Escribiendo valores
Dusk proporciona una variedad de métodos para interactuar con formularios y elementos de entrada. Primero, vamos a dar un vistazo a un ejemplo de escribir texto dentro de un campo de entrada:
$browser->type('email', '[email protected]');
Nota que, aunque el método acepta uno si es necesario, no estamos obligados a pasar un selector CSS dentro del método type
. Si un selector CSS no es proporcionado, Dusk buscará un campo de entrada con el atributo name
dado. Finalmente, Dusk intentará encontrar un textarea
con el atributo name
dado.
Para agregar texto a un campo sin limpiar su contenido, puedes usar el método append
:
$browser->type('tags', 'foo') ->append('tags', ', bar, baz');
Puedes limpiar el valor de un campo usando el método clear
:
$browser->clear('email');
Listas desplegables
Para seleccionar un valor en un cuadro de selección de lista desplegable, puedes usar el método select
. Al igual que el método type
, el método select
no requiere un selector completo de CSS. Al momento de pasar un valor al método select
, deberías pasar el valor de opción a resaltar en lugar del texto mostrado en pantalla:
$browser->select('size', 'Large');
Puedes seleccionar una opción aleatoria al omitir el segundo parámetro:
$browser->select('size');
Casillas de verificación
Para «marcar» un campo de casilla de verificación, puedes usar el método check
. Al igual que muchos otros métodos relacionados con entradas, un selector CSS completo no es obligatorio. Si un selector que coincida exactamente no puede ser encontrado, Dusk buscará una casilla de verificación con un atributo name
coincidente:
$browser->check('terms'); $browser->uncheck('terms');
Botones de radio
Para «seleccionar» una opción de botón de radio, puedes usar el método radio
. Al igual que muchos otros métodos relacionados con campos, un selector CSS completo no es obligatorio. Si un selector que coincida exactamente no puede ser encontrado, Dusk buscará un radio con atributos name
y value
coincidentes:
$browser->radio('version', 'php7');
Adjuntando archivos
El método attach
puede ser usado para adjuntar un archivo a un elemento de entrada file
. Al igual que muchos otros métodos relacionados con campos, un selector CSS completo no es obligatorio. Si un selector que coincida exactamente no puede ser encontrado, Dusk buscará un campo de archivo con atributo name
coincidente:
$browser->attach('photo', __DIR__.'/photos/me.png');
La función attach
requiere que la extensión de PHP Zip
esté instalada y habilitada en tu servidor.
Usando el teclado
El método keys
permite que proporciones secuencias de entrada más complejas para un elemento dado que lo permitido normalmente por el método type
. Por ejemplo, puedes mantener presionada las teclas modificadoras al introducir valores. En este ejemplo, la tecla shift
será mantenida presionada mientras la palabra taylor
es introducida dentro del elemento que coincida con el selector dado. Después de que la palabra taylor
sea tipeada, la palabra otwell
será tipeada sin alguna tecla modificadora:
$browser->keys('selector', ['{shift}', 'taylor'], 'otwell');
Incluso puedes enviar una «tecla de función» al selector CSS principal que contiene tu aplicación:
$browser->keys('.app', ['{command}', 'j']);
Todas las teclas modificadoras se envuelven entre corchetes {}
y coinciden con las constantes definidas en la clase Facebook\WebDriver\WebDriverKeys
, la cual puede ser encontrada en GitHub.
Usando el Ratón
Haciendo clic sobre elementos
El método click
puede ser usado para «clickear» sobre un elemento que coincida con el selector dado:
$browser->click('.selector');
Mouseover
El método mouseover
puede ser usado cuando necesitas mover el ratón sobre un elemento que coincida con el selector dado:
$browser->mouseover('.selector');
Arrastrar y soltar
El método drag
puede ser usado para arrastrar un elemento que coincida con el selector dado hasta otro elemento:
$browser->drag('.from-selector', '.to-selector');
O, puedes arrastrar un elemento en una única dirección:
$browser->dragLeft('.selector', 10); $browser->dragRight('.selector', 10); $browser->dragUp('.selector', 10); $browser->dragDown('.selector', 10);
Diálogos de JavaScript
Dusk provee de varios métodos para interactuar con Diálogos de JavaScript:
// Wait for a dialog to appear: $browser->waitForDialog($seconds = null); // Assert that a dialog has been displayed and that its message matches the given value: $browser->assertDialogOpened('value'); // Type the given value in an open JavaScript prompt dialog: $browser->typeInDialog('Hello World');
Para cerrar un Diálogo de JavaScript abierto, haga clic en el botón Aceptar o OK:
$browser->acceptDialog();
Para cerrar un Diálogo de JavaScript abierto, haga clic en el botón Cancelar (solo para un diálogo de confirmación):
$browser->dismissDialog();
Alcance de selectores
Algunas veces puedes querer ejecutar varias operaciones dentro del alcance de un selector dado. Por ejemplo, puedes querer comprobar que algunos textos existen únicamente dentro de una tabla y después presionar un botón dentro de la tabla. Puedes usar el método with
para completar esta tarea. Todas las operaciones ejecutadas dentro de la función de retorno (callback) dada al método with
serán exploradas en el selector original:
$browser->with('.table', function ($table) { $table->assertSee('Hello World') ->clickLink('Delete'); });
Esperando por elementos
Al momento de probar aplicaciones que usan JavaScript de forma extensiva, frecuentemente se vuelve necesario «esperar» por ciertos elementos o datos estén disponibles antes de proceder con una prueba. Dusk hace esto fácilmente. Usando una variedad de métodos, puedes esperar que los elementos estén visibles en la página e incluso esperar hasta que una expresión de JavaScript dada se evalúe como true
.
Esperando
Si necesitas pausar la prueba por un número de milisegundos dado, usa el método pause
:
$browser->pause(1000);
Esperando por selectores
El método waitFor
puede ser usado para pausar la ejecución de la prueba hasta que el elemento que coincida con el selector CSS dado sea mostrado en la página. De forma predeterminada, esto pausará la prueba por un máximo de cinco segundos antes de arrojar una excepción. Si es necesario, puedes pasar un umbral de tiempo de expiración personalizado como segundo argumento del método:
// Wait a maximum of five seconds for the selector... $browser->waitFor('.selector'); // Wait a maximum of one second for the selector... $browser->waitFor('.selector', 1);
También puede esperar hasta que el selector dado no se encuentre en la página:
$browser->waitUntilMissing('.selector'); $browser->waitUntilMissing('.selector', 1);
Estableciendo el alcance de selectores cuando estén disponibles
Ocasionalmente, puedes querer esperar por un selector dado y después interactuar con el elemento que coincida con el selector. Por ejemplo, puedes querer esperar hasta que una ventana modal esté disponible y después presionar el botón «OK» dentro de esa ventana. El método whenAvailable
puede ser usado en este caso. Todas las operaciones de elementos ejecutadas dentro de la función de retorno (callback) dada serán ejecutadas dentro del selector original:
$browser->whenAvailable('.modal', function ($modal) { $modal->assertSee('Hello World') ->press('OK'); });
Esperando por texto
El método waitForText
puede ser usado para esperar hasta que el texto dado sea mostrado en la página:
// Wait a maximum of five seconds for the text... $browser->waitForText('Hello World'); // Wait a maximum of one second for the text... $browser->waitForText('Hello World', 1);
Puedes usar el método waitUntilMissingText
para esperar hasta que el texto mostrado haya sido removido de la página:
// Wait a maximum of five seconds for the text to be removed... $browser->waitUntilMissingText('Hello World'); // Wait a maximum of one second for the text to be removed... $browser->waitUntilMissingText('Hello World', 1);
Esperando por enlaces
El método waitForLink
puede ser usado para esperar hasta que un enlace dado sea mostrado en la página:
// Wait a maximum of five seconds for the link... $browser->waitForLink('Create'); // Wait a maximum of one second for the link... $browser->waitForLink('Create', 1);
Esperando por la localización de la página
Al momento de hacer una comprobación de ruta tal como $browser->assertPathIs('/home')
, la comprobación puede fallar si window.location.pathname
está siendo actualizada asincrónicamente. Puedes usar el método waitForLocation
para esperar por la localización que tenga un valor dado:
$browser->waitForLocation('/secret');
También puede esperar la localización de una ruta con nombre:
$browser->waitForRoute($routeName, $parameters);
Esperando por recargas de página
Si necesita hacer aserciones después de que se haya recargado una página, usa el método waitForReload
:
$browser->click('.some-action') ->waitForReload() ->assertSee('something');
Esperando por expresiones de JavaScript
Algunas veces puedes querer pausar la ejecución de una prueba hasta que una expresión de JavaScript dada se evalúe a true
. Puedes completar fácilmente esto usando el método waitUntil
. Al momento de pasar una expresión a este método, no necesitas incluir al final la palabra clave return
o un punto y coma ;
:
// Wait a maximum of five seconds for the expression to be true... $browser->waitUntil('App.dataLoaded'); $browser->waitUntil('App.data.servers.length > 0'); // Wait a maximum of one second for the expression to be true... $browser->waitUntil('App.data.servers.length > 0', 1);
Esperando por expresiones de Vue
Los siguientes métodos puedes ser usados para esperar hasta que un atributo de componente de Vue dado tenga un determinado valor:
// Wait until the component attribute contains the given value... $browser->waitUntilVue('user.name', 'Taylor', '@user'); // Wait until the component attribute doesn't contain the given value... $browser->waitUntilVueIsNot('user.name', null, '@user');
Esperando por una función de retorno
Muchos de los métodos de «espera» en Dusk confían en el método waitUsing
subyacente. Puedes usar este método directamente para esperar por una función de retorno (callback) dada que devuelva true
. El método waitUsing
acepta el número máximo de segundos para esperar la Closure, el intervalo en el cual la Closure debería ser evaluada, la Closure y un mensaje opcional de falla:
$browser->waitUsing(10, 1, function () use ($something) { return $something->isReady(); }, "Something wasn't ready in time.");
Haciendo aserciones de Vue
Inclusive Dusk permite que hagas comprobaciones en el estado de componente de datos de Vue. Por ejemplo, imagina que tu aplicación contiene el siguiente componente de Vue:
// HTML... <profile dusk="profile-component"></profile> // Component Definition... Vue.component('profile', { template: '<div>{{ user.name }}</div>', data: function () { return { user: { name: 'Taylor' } }; } });
Puedes comprobar el estado del componente de Vue de esta manera:
/** * A basic Vue test example. * * @return void */ public function testVue() { $this->browse(function (Browser $browser) { $browser->visit('/') ->assertVue('user.name', 'Taylor', '@profile-component'); }); }
Aserciones disponibles
Dusk proporciona una variedad de aserciones que puedes hacer en tu aplicación. Todas las aserciones disponibles están documentadas en la siguiente lista:
assertTitle
assertTitleContains
assertUrlIs
assertSchemeIs
assertSchemeIsNot
assertHostIs
assertHostIsNot
assertPortIs
assertPortIsNot
assertPathBeginsWith
assertPathIs
assertPathIsNot
assertRouteIs
assertQueryStringHas
assertQueryStringMissing
assertFragmentIs
assertFragmentBeginsWith
assertFragmentIsNot
assertHasCookie
assertCookieMissing
assertCookieValue
assertPlainCookieValue
assertSee
assertDontSee
assertSeeIn
assertDontSeeIn
assertSourceHas
assertSourceMissing
assertSeeLink
assertDontSeeLink
assertInputValue
assertInputValueIsNot
assertChecked
assertNotChecked
assertRadioSelected
assertRadioNotSelected
assertSelected
assertNotSelected
assertSelectHasOptions
assertSelectMissingOptions
assertSelectHasOption
assertValue
assertVisible
assertPresent
assertMissing
assertDialogOpened
assertEnabled
assertDisabled
assertButtonEnabled
assertButtonDisabled
assertFocused
assertNotFocused
assertVue
assertVueIsNot
assertVueContains
assertVueDoesNotContain
assertTitle
Comprueba que el título de la página coincida con el texto dado:
$browser->assertTitle($title);
assertTitleContains
Comprueba que el título de página contenga el texto dado:
$browser->assertTitleContains($title);
assertUrlIs
Comprueba que la URL actual (sin la cadena de consulta) coincida con la cadena dada:
$browser->assertUrlIs($url);
assertSchemeIs
Comprueba que el esquema de la URL actual coincide con el esquema dado:
$browser->assertSchemeIs($scheme);
assertSchemeIsNot
Comprueba que el esquema de la URL actual no coincide con el esquema dado:
$browser->assertSchemeIsNot($scheme);
assertHostIs
Comprueba que el Host de la URL actual coincide con el Host dado:
$browser->assertHostIs($host);
assertHostIsNot
Comprueba que el Host de la URL actual no coincide con el Host dado:
$browser->assertHostIsNot($host);
assertPortIs
Comprueba que el puerto de la URL actual coincide con el puerto dado:
$browser->assertPortIs($port);
assertPortIsNot
Comprueba que el puerto de la URL actual no coincide con el puerto dado:
$browser->assertPortIsNot($port);
assertPathBeginsWith
Comprueba que la ruta de la URL actual comience con la ruta dada:
$browser->assertPathBeginsWith($path);
assertPathIs
Comprueba que la ruta actual coincida con la ruta dada:
$browser->assertPathIs('/home');
assertPathIsNot
Comprueba que la ruta actual no coincida con la ruta dada:
$browser->assertPathIsNot('/home');
assertRouteIs
Comprueba que la URL actual coincida con la URL de ruta nombrada dada:
$browser->assertRouteIs($name, $parameters);
assertQueryStringHas
Comprueba que el parámetro de cadena para una consulta dada está presente:
$browser->assertQueryStringHas($name);
Comprueba que el parámetro de cadena para una consulta dada está presente y tiene un valor dado:
$browser->assertQueryStringHas($name, $value);
assertQueryStringMissing
Comprueba que el parámetro de cadena para una consulta dada está ausente:
$browser->assertQueryStringMissing($name);
assertFragmentIs
Comprueba que el fragmento actual coincide con el fragmento dado:
$browser->assertFragmentIs('anchor');
assertFragmentBeginsWith
Comprueba que el fragmento actual comienza con el fragmento dado:
$browser->assertFragmentBeginsWith('anchor');
assertFragmentIsNot
Comprueba que el fragmento actual no coincide con el fragmento dado:
$browser->assertFragmentIsNot('anchor');
assertHasCookie
Comprueba que el cookie dado está presente:
$browser->assertHasCookie($name);
assertCookieMissing
Comprueba que el cookie dado no está presente:
$browser->assertCookieMissing($name);
assertCookieValue
Comprueba que un cookie tenga un valor dado:
$browser->assertCookieValue($name, $value);
assertPlainCookieValue
Comprueba que un cookie desencriptado tenga un valor dado:
$browser->assertPlainCookieValue($name, $value);
assertSee
Comprueba que el texto dado está presente en la página:
$browser->assertSee($text);
assertDontSee
Comprueba que el texto dado no está presente en la página:
$browser->assertDontSee($text);
assertSeeIn
Comprueba que el texto dado está presente dentro del selector:
$browser->assertSeeIn($selector, $text);
assertDontSeeIn
Comprueba que el texto dado no está presente dentro del selector:
$browser->assertDontSeeIn($selector, $text);
assertSourceHas
Comprueba que el código fuente dado está presente en la página:
$browser->assertSourceHas($code);
assertSourceMissing
Comprueba que el código fuente dado no está presente en la página:
$browser->assertSourceMissing($code);
assertSeeLink
Comprueba que el enlace dado está presente en la página:
$browser->assertSeeLink($linkText);
assertDontSeeLink
Comprueba que el enlace dado está no presente en la página:
$browser->assertDontSeeLink($linkText);
assertInputValue
Comprueba que el campo de entrada dado tiene el valor dado:
$browser->assertInputValue($field, $value);
assertInputValueIsNot
Comprueba que el campo de entrada dado no tiene el valor dado:
$browser->assertInputValueIsNot($field, $value);
assertChecked
Comprueba que la casilla de verificación está marcada:
$browser->assertChecked($field);
assertNotChecked
Comprueba que la casilla de verificación no está marcada:
$browser->assertNotChecked($field);
assertRadioSelected
Comprueba que el campo de radio está seleccionado:
$browser->assertRadioSelected($field, $value);
assertRadioNotSelected
Comprueba que el campo de radio no está seleccionado:
$browser->assertRadioNotSelected($field, $value);
assertSelected
Comprueba que la lista desplegable tiene seleccionado el valor dado:
$browser->assertSelected($field, $value);
assertNotSelected
Comprueba que la lista desplegable no tiene seleccionado el valor dado:
$browser->assertNotSelected($field, $value);
assertSelectHasOptions
Comprueba que el arreglo de valores dado está disponible para ser seleccionado:
$browser->assertSelectHasOptions($field, $values);
assertSelectMissingOptions
Comprueba que el arreglo de valores dado no está disponible para ser seleccionado:
$browser->assertSelectMissingOptions($field, $values);
assertSelectHasOption
Comprueba que el valor dado está disponible para ser seleccionado en el campo dado:
$browser->assertSelectHasOption($field, $value);
assertValue
Comprueba que el elemento que coincida con el selector dado tenga el valor dado:
$browser->assertValue($selector, $value);
assertVisible
Comprueba que el elemento que coincida con el selector dado sea visible:
$browser->assertVisible($selector);
assertPresent
Comprueba que el elemento que coincida con el selector dado está presente:
$browser->assertPresent($selector);
assertMissing
Comprueba que el elemento que coincida con el selector dado no sea visible:
$browser->assertMissing($selector);
assertDialogOpened
Comprueba que un diálogo JavaScript con un mensaje dado ha sido abierto:
$browser->assertDialogOpened($message);
assertEnabled
Comprueba que el campo dado está activado:
$browser->assertEnabled($field);
assertDisabled
Comprueba que el campo dado está desactivado:
$browser->assertDisabled($field);
assertButtonEnabled
Comprueba que el botón dado está activado:
$browser->assertButtonEnabled($button);
assertButtonDisabled
Comprueba que el botón dado está desactivado:
$browser->assertButtonDisabled($button);
assertFocused
Comprueba que el campo dado está enfocado:
$browser->assertFocused($field);
assertNotFocused
Comprueba que el campo dado no está enfocado:
$browser->assertNotFocused($field);
assertVue
Comprueba que una propiedad de datos de un componente de Vue dado coincida con el valor dado:
$browser->assertVue($property, $value, $componentSelector = null);
assertVueIsNot
Comprueba que una propiedad de datos de un componente de Vue dado no coincida con el valor dado:
$browser->assertVueIsNot($property, $value, $componentSelector = null);
assertVueContains
Comprueba que una propiedad de datos de un componente de Vue dado es un arreglo y contiene el valor dado:
$browser->assertVueContains($property, $value, $componentSelector = null);
assertVueDoesNotContain
Comprueba que una propiedad de datos de un componente de Vue dado es un arreglo y no contiene el valor dado:
$browser->assertVueDoesNotContain($property, $value, $componentSelector = null);
Páginas
Alguna veces, las pruebas requieren que varias acciones complicadas sean ejecutadas en secuencia. Esto puede hacer tus pruebas más difíciles de leer y entender. Las páginas permiten que definas acciones expresivas que entonces pueden ser ejecutadas en una página dada usando un solo método. Las páginas también permiten que definas abreviaturas para selectores comunes para tu aplicación o una página única.
Generando páginas
Para generar un objeto de página, usa el comando Artisan dusk:page
. Todos los objetos de página serán colocados en el directorio tests/Browser/Pages
:
php artisan dusk:page Login
Configurando páginas
De forma predeterminada, las páginas tienen tres métodos: url
, assert
y elements
. Discutiremos los métodos url
y assert
ahora. El método elements
será discutido con más detalle debajo.
El método url
El método url
debería devolver la ruta de la URL que representa la página. Dusk usará esta URL al momento de navegar a la página en el navegador:
/** * Get the URL for the page. * * @return string */ public function url() { return '/login'; }
El método assert
El método assert
puede hacer algunas aserciones necesarias para verificar que el navegador en realidad está en la página dada. Completar este método no es necesario; sin embargo, eres libre de hacer estas aserciones si lo deseas. Estas aserciones serán ejecutadas automáticamente al momento de navegar hacia la página:
/** * Assert that the browser is on the page. * * @return void */ public function assert(Browser $browser) { $browser->assertPathIs($this->url()); }
Navegando hacia las páginas
Una vez que se ha configurado una página, puedes navegar a ella utilizando el método visit
:
use Tests\Browser\Pages\Login; $browser->visit(new Login);
A veces es posible que ya estés en una página determinada y necesitas «cargar» los selectores y métodos dentro del contexto de prueba actual. Esto es común al momento de presionar un botón y ser redireccionado a una página dada sin navegar explícitamente a ésta. 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');
Selectores abreviados
El método elements
de páginas permite que definas abreviaturas rápidas y fáciles de recordar para cualquier selector CSS en tu página. Por ejemplo, vamos a definir una abreviación para el campo «email» de la página login de la aplicación:
/** * Get the element shortcuts for the page. * * @return array */ public function elements() { return [ '@email' => 'input[name=email]', ]; }
Ahora, puedes usar este selector de abreviación en cualquier lugar que usarías un selector de CSS completo:
$browser->type('@email', '[email protected]');
Selectores de abreviaturas globales
Después de instalar Dusk, una clase Page
básica será colocada en tu directorio tests/Browser/Pages
. Esta clase contiene un método siteElements
el cual puede ser usado para definir selectores de abreviaturas globales que deberían estar disponibles en todas las páginas de tu aplicación:
/** * Get the global element shortcuts for the site. * * @return array */ public static function siteElements() { return [ '@element' => '#selector', ]; }
Métodos de página
Además de los métodos predeterminados definidos en páginas, puedes definir métodos adicionales, los cuales pueden ser usados en cualquier parte de tus pruebas. Por ejemplo, vamos a imaginar que estamos construyendo una aplicación para administració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 { // Other page methods... /** * Create a new playlist. * * @param \Laravel\Dusk\Browser $browser * @param string $name * @return void */ public function createPlaylist(Browser $browser, $name) { $browser->type('name', $name) ->check('share') ->press('Create Playlist'); } }
Una vez que el método ha sido definido, puedes usarlo dentro de cualquier prueba que utilice la página. La instancia de navegador será pasada automáticamente al método de la página:
use Tests\Browser\Pages\Dashboard; $browser->visit(new Dashboard) ->createPlaylist('My Playlist') ->assertSee('My Playlist');
Componentes
Los componentes son similares a “los objetos de página” de Dusk, pero son planeados para partes de UI y funcionalidades que sean reusadas en otras partes de tu aplicación, tal como una barra de navegación o ventana de notificación. Como tal, los componentes no son enlazados a URLs específicas.
Generando componentes
Para generar un componente, usa el comando Artisan dusk:component
. Los nuevos componentes son colocados en el directorio tests/Browser/Components
:
php artisan dusk:component DatePicker
Como se muestra antes, un «calendario» es un ejemplo de un componente que puede existir en cualquier parte de tu aplicación en una variedad de páginas. Puede volverse complejo escribir manualmente lógica de automatización de navegador para seleccionar una fecha entre docenas de pruebas en cualquier parte de tu software de prueba. En lugar de esto, podemos definir un componente de Dusk para representar el calendario, permitiendo 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 { /** * Get the root selector for the component. * * @return string */ public function selector() { return '.date-picker'; } /** * Assert that the browser page contains the component. * * @param Browser $browser * @return void */ public function assert(Browser $browser) { $browser->assertVisible($this->selector()); } /** * Get the element shortcuts for the component. * * @return array */ public function elements() { return [ '@date-field' => 'input.datepicker-input', '@year-list' => 'div > div.datepicker-years', '@month-list' => 'div > div.datepicker-months', '@day-list' => 'div > div.datepicker-days', ]; } /** * Select the given date. * * @param \Laravel\Dusk\Browser $browser * @param int $year * @param int $month * @param int $day * @return void */ public function selectDate($browser, $year, $month, $day) { $browser->click('@date-field') ->within('@year-list', function ($browser) use ($year) { $browser->click($year); }) ->within('@month-list', function ($browser) use ($month) { $browser->click($month); }) ->within('@day-list', function ($browser) use ($day) { $browser->click($day); }); } }
Usando componentes
Una vez que el componente ha sido definido, fácilmente podemos seleccionar una fecha dentro del calendario desde cualquier prueba. Y, si la lógica necesaria para seleccionar una fecha cambia, solamente necesitaremos 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 { /** * A basic component test example. * * @return void */ public function testBasicExample() { $this->browse(function (Browser $browser) { $browser->visit('/') ->within(new DatePicker, function ($browser) { $browser->selectDate(2019, 1, 30); }) ->assertSee('January'); }); } }
Integración continua
Antes de añadir un archivo de configuración de integración continua, asegúrate de que tu archivo .env.testing
contenga una línea APP_URL
con un valor de http://127.0.0.1:8000
.
CircleCI
Si estás usando CircleCI para ejecutar tus pruebas de Dusk, puedes usar este archivo de configuración como punto de partida. Al igual que con TravisCI, usaremos el comando php artisan serve
para ejecutar el servidor web integrado de PHP:
version: 2 jobs: build: steps: - run: sudo apt-get install -y libsqlite3-dev - run: cp .env.testing .env - run: composer install -n --ignore-platform-reqs - run: php artisan key:generate - run: php artisan dusk:chrome-driver - run: npm install - run: npm run production - run: vendor/bin/phpunit - run: name: Start Chrome Driver command: ./vendor/laravel/dusk/bin/chromedriver-linux background: true - run: name: Run Laravel Server command: php artisan serve background: true - run: name: Run Laravel Dusk Tests command: php artisan dusk - store_artifacts: path: tests/Browser/screenshots
Codeship
Para ejecutar pruebas de Dusk en Codeship, agrega los siguientes comandos a tu proyecto Codeship. Estos comandos son sólo un punto de partida y eres libre de agregar los comandos adicionales que necesites:
phpenv local 7.2 cp .env.testing .env mkdir -p ./bootstrap/cache composer install --no-interaction --prefer-dist php artisan key:generate php artisan dusk:chrome-driver nohup bash -c "php artisan serve 2>&1 &" && sleep 5 php artisan dusk
Heroku CI
Para ejecutar tus pruebas de 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 > /dev/null 2>&1 &' && php artisan dusk" } } } }
Travis CI
Para ejecutar tus pruebas de Dusk en Travis CI, usa la siguiente configuración en el archivo .travis.yml
. Ya que Travis CI no es un entorno gráfico, necesitaremos tomar algunos pasos extras con el propósito de ejecutar un navegador Chrome. Además, usaremos php artisan serve
para ejecutar el servidor web integrado de PHP:
language: php php: - 7.3 addons: chrome: stable install: - cp .env.testing .env - travis_retry composer install --no-interaction --prefer-dist --no-suggest - 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 & script: - php artisan dusk
GitHub Actions
Si estás usando acciones de GitHub para ejecutar tus pruebas de Dusk, puedes usar este archivo de configuración como punto de partida. Igual que TravisCI, usaremos el comando php artisan serve
para ejecutar el servidor integrado de PHP:
name: CI on: [push] jobs: dusk-php: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - name: Prepare The Environment run: cp .env.example .env - name: Create Database run: 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 --no-suggest --prefer-dist --optimize-autoloader - name: Generate Application Key run: php artisan key:generate - name: Upgrade Chrome Driver run: php artisan dusk:chrome-driver - name: Start Chrome Driver run: ./vendor/laravel/dusk/bin/chromedriver-linux & - name: Run Laravel Server run: php artisan serve & - name: Run Dusk Tests run: php artisan dusk
Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.
Lección anterior Pruebas de consola - Documentación de Laravel 6 Lección siguiente Pruebas de Base de Datos - Documentación de Laravel 6