In the previous part of this series, I completed the ToDo app. Today, I am going to test this app using Laravel Dusk. I will start this article with a brief introduction of Laravel Dusk, how you can set up Laravel Dusk and then go into the process of testing the ToDo application.
What is Laravel Dusk?
Laravel Dusk gives an expressive, easy-to-use browser automation and testing API. By default, Dusk does not require you to install JDK or Selenium on your local computer. Instead, Dusk uses a standalone ChromeDriver development..
Dusk is a Laravel package that performs end-to-end (E2E) tests on Laravel applications. Giving client-side testing by running tests in a browser, Dusk permits engineers to see client-side features tested in real time, mirroring how a client would utilize them
Install Laravel Dusk
Laravel Dusk can be installed by running the following command:
composer require laravel/dusk
Once the installation finishes, I will register it inside the `register()` method in `AppServiceProvider`. For this, go to app/Providers folder and open AppServiceProvider.php file. Add the following line right before the start of the class:
use Laravel\Dusk\DuskServiceProvider;
Next, in the `register()` method, paste the following code:
public function register() { if ($this->app->environment('local', 'testing')) { $this->app->register(DuskServiceProvider::class); } }
At this point, `AppServiceProvider` class will look like this:
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use Illuminate\Support\Facades\Schema; use Laravel\Dusk\DuskServiceProvider; class AppServiceProvider extends ServiceProvider { /** * Bootstrap any application services. * * @return void */ public function boot() { // Schema::defaultStringLength(191); } /** * Register any application services. * * @return void */ public function register() { if ($this->app->environment('local', 'testing')) { $this->app->register(DuskServiceProvider::class); } } }
Now, run the following command to install Laravel Dusk:
php artisan dusk:install
Once the command is completed, the Browser directory will be created inside the tests directory (this will contain an Example Test file). In this directory, I will create all the tests for browser automation.
Next, I will describe the testing process of the ToDo app.
You might also like: Automate Code Testing With PHP Continuous Integration
Creating Browser Test Cases for the ToDo App
I will use the default browser (Chrome) for the tests.
First of all, run the following command to create a new Test file:
php artisan dusk:make TodoTest
Once the command finishes, it will create a new test file with the name TodoTest inside the Browser directory. This file will contain an example test case method `testExample()`. Remove this method from the file.
Before I start adding the methods for test cases, open .env file and add the full app URL in the APP_URL constant.
APP_URL=http://localhost/todoapplaravel/public
Now, I could start writing the test cases.
User Registration Test
I will begin by creating a new test function which will test user registration process and check whether the user is redirected to the dashboard.
Inside the `TodoTest` class, create a new function with the name `testRegister()`. Paste the following code in it:
public function testRegister() { $this->browse(function ($browser) { $browser->visit('register') ->type('name', 'Tayor Otwell') ->type('email', '[email protected]') ->type('password', 'ahmedkhan') ->type('password_confirmation', 'ahmedkhan') ->attach('userimage', 'C:\images\taylor.jpg') ->press('Register') ->assertPathIs('/todoapplaravel/public/todo'); }); }
In the above code, I called the `browse` method along with the `$browser` instance, which is automatically passed by Dusk and used to make assertion for the application. First, I used the `visit()` method to direct the browser to the register page. Then, in the `type` method, I first defined the name of the input field and after the comma, I assigned its value. Since I am using a file input type in the registration form, I have used the `attach` method to attach the file to the input. I entered the name of the type file input field and then defined the path where the image is saved at the local machine. Next, I used `press` (used to press the button on the web page). Inside this, I defined the button to press (in this case, it is Register). Finally, I checked the assert that the user is redirected to the dashboard i.e. ‘/todo/’ by using the `assertPathIs` method. I need to add the full URL, as shown in the browser after the ‘localhost’, i.e. ‘/todoapplaravel/public/todo’.
Create a New ToDo Test
Now, create a new method with the name `testCreateTodo()`. Add the following code in it.
public function testCreateTodo() { $this->browse(function ($browser) { $browser->visit('todo') ->clickLink('Add Todo') ->type('todo', 'Testing it With Dusk') ->type('category', 'dusk') ->type('description', 'This is created with dusk') ->press('Add') ->assertPathIs('/todoapplaravel/public/todo'); }); }
After redirecting to the ‘todo’, I have used the `clickLink` method to click on the add todo, since it is a link, not a button. Next, I added todo input values. Once done, I pressed the Add button. Next, I am asserting that it is redirected to the dashboard. The todo item has been added successfully. If not, then assert would fail.
View the Todo Test
Before creating this test, I need to edit the dashboard.php file. I will add an id to all the icons so that I can click them using the automation testing. For this, go to the resources/views/todo directory and open the dashboard.php file. Now, replace the code in this file with the following:
@extends('layouts.app') @section('title', 'Home ') @section('content') <div class="row"> <div class="col-md-9"> <ul class="list-group"> @if($todos != false) @foreach ($todos as $todo) <li class="list-group-item"><a id="view{{$todo->id}}" class="secondary-content" href="{{url('/todo/'.$todo->id)}}"><span class="glyphicon glyphicon-triangle-right"></span></a><a id="edit{{$todo->id}}" class="secondary-content" href="{{url('/todo/'.$todo->id).'/edit'}}"><span class="glyphicon glyphicon-pencil"></span></a><a id="delete{{$todo->id}}" href="#" class="secondary-content" onclick="event.preventDefault(); document.getElementById('delete-form').submit();"><span class="glyphicon glyphicon-trash"></span></a><form id="delete-form" action="{{url('/todo/'.$todo->id)}}" method="POST" style="display: none;"> {{ method_field('DELETE') }}{{ csrf_field() }} </form> {{$todo->todo}} </li> @endforeach @else <li class="list-group-item"> No Todo added yet <a href="{{ url('/todo/create') }}"> click here</a> to add new todo. </li> @endif </ul> </div> <div class="col-md-3"> <img class="img-responsive img-circle" src="{{asset('storage/'.$image)}}"> </div> </div> @endsection
In the above code, I gave an id to the view,edit & delete. This is a concatenation of the view and the id of a todo i.e. `id=”view{{$todo->id}}”` for view, `id=”edit{{$todo->id}}”` for edit and `id=”delete{{$todo->id}}”` for delete.
Now, I will create the todo test for viewing todo. For this, go to the TodoTest.php file and add a new method `testViewTodo()` with the following code:
public function testViewTodo() { $this->browse(function ($browser) { $browser->visit('todo') ->assertVisible('#view1') ->visit( $browser->attribute('#view1', 'href') ) ->assertPathIs('/todoapplaravel/public/todo/1') ->clickLink('Edit') ->type('description', 'Testing it with dusk again') ->press('Update') ->assertPathIs('/todoapplaravel/public/todo/1'); }); }
In the above code, I first visited ‘todo’ and then asserted that id #view1 exists in the dashboard. Then, I visited this link using the `visit` method. Inside this method, I defined which attribute to click using the `attribute` method. Next, I asserted its path. If it is valid, I called the clickLink method to click on the Edit link, which is visible on that page. Next, I have edited its description using the `type` method and then pressed the Update button using the press method. Next, I checked the path again to see that it redirect back to the same todo or not using `assertPathis` method.
Stop Wasting Time on Servers
Cloudways handle server management for you so you can focus on creating great apps and keeping your clients happy.
Edit the Todo Test
Now, create a new function with name the `testEditTodo`. Add the following code to it:
public function testEditTodo() { $this->browse(function ($browser) { $browser->visit('todo') ->assertVisible('#edit1') ->visit( $browser->attribute('#edit1', 'href') ) ->type('description', 'Testing it with dusk again') ->press('Update') ->assertPathIs('/todoapplaravel/public/todo/1'); }); }
In The above code, I first redirected to the dashboard and then clicked the edit icon, updated the todo description and then asserted that the path is same or not.
Delete a Todo Test
Now, create a new function with the name `testDeleteTodo`. Add the following code to it:
public function testDeleteTodo() { $this->browse(function ($browser) { $browser->visit('todo') ->assertVisible('#delete1') ->visit( $browser->attribute('#delete1', 'href') ) ->assertPathIs('/todoapplaravel/public/todo'); }); }
Logout Test
Now, create a new function with the name `testLogout()` and add the following code to it:
public function testLogout() { $this->browse(function ($browser) { $browser->visit('todo') ->clickLink('Logout') ->assertPathIs('/todoapplaravel/public/login'); }); }
After registration, the user is automatically redirected to Login page. That’s why, I have not created the login test before. Now, create a new function with the name `testLogin` and paste the following code in it:
public function testLogin() { $this->browse(function ($browser) { $browser->visit('login') ->type('email', '[email protected]') ->type('password', 'ahmedkhan') ->press('Login') ->assertPathIs('/todoapplaravel/public/todo'); }); }
At this point, all the test cases for the ToDo app have been created. The complete TodoTest file will look like the following:
<?php namespace Tests\Browser; use Tests\DuskTestCase; use Illuminate\Foundation\Testing\DatabaseMigrations; class TodoTest extends DuskTestCase { /** * Register test. * * @return void */ public function testRegister() { $this->browse(function ($browser) { $browser->visit('register') ->type('name', 'Tayor Otwell') ->type('email', '[email protected]') ->type('password', 'ahmedkhan') ->type('password_confirmation', 'ahmedkhan') ->attach('userimage', 'C:\Users\ahmed.khan\Downloads\CreatingToDoApplicationinLaravel5.4CreatingAuthToDoViewsRoutesandModifyingController\images\taylor.jpg') ->press('Register') ->assertPathIs('/todoapplaravel/public/todo'); }); } /** * Create Todo test. * * @return void */ public function testCreateTodo() { $this->browse(function ($browser) { $browser->visit('todo') ->clickLink('Add Todo') ->type('todo', 'Testing it With Dusk') ->type('category', 'dusk') ->type('description', 'This is created with dusk') ->press('Add') ->assertPathIs('/todoapplaravel/public/todo'); }); } /** * View and Edit Todo Test. * * @return void */ public function testViewTodo() { $this->browse(function ($browser) { $browser->visit('todo') ->assertVisible('#view1') ->visit( $browser->attribute('#view1', 'href') ) ->assertPathIs('/todoapplaravel/public/todo/1') ->clickLink('Edit') ->type('description', 'Testing it with dusk again') ->press('Update') ->assertPathIs('/todoapplaravel/public/todo/1'); }); } /** * Edit todo test. * * @return void */ public function testEditTodo() { $this->browse(function ($browser) { $browser->visit('todo') ->assertVisible('#edit1') ->visit( $browser->attribute('#edit1', 'href') ) ->type('description', 'Testing it with dusk again') ->press('Update') ->assertPathIs('/todoapplaravel/public/todo/1'); }); } /** * Delete Todo test. * * @return void */ public function testDeleteTodo() { $this->browse(function ($browser) { $browser->visit('todo') ->assertVisible('#delete1') ->visit( $browser->attribute('#delete1', 'href') ) ->assertPathIs('/todoapplaravel/public/todo'); }); } /* * Logout test. * * @return void */ public function testLogout() { $this->browse(function ($browser) { $browser->visit('todo') ->clickLink('Logout') ->assertPathIs('/todoapplaravel/public/login'); }); } /** * Login test. * * @return void */ public function testLogin() { $this->browse(function ($browser) { $browser->visit('login') ->type('email', '[email protected]') ->type('password', 'ahmedkhan') ->press('Login') ->assertPathIs('/todoapplaravel/public/todo'); }); } }
This test case file has been added to the todo app Laravel repo on the GitHub.
One Command To Test Them All
On the command line, run the following command to run the automation tests:
php artisan dusk
Check out the following GIF to see browser testing with Laravel Dusk in action:
Concluding The Series
This series focuses on the Laravel powered ToDo application, starting off with setting up migration tables, controller and models. Then, creating user authentication, views and setup ToDo functionality. In the final part of the series, I carried out browser testing of Laravel applications using Laravel Dusk.
Shahzeb Ahmed
Shahzeb is a Digital Marketer with a Software Engineering background, works as a Community Manager — PHP Community at Cloudways. He is growth ambitious and aims to learn & share information about PHP & Laravel Development through practice and experimentation. He loves to travel and explore new ideas whenever he finds time. Get in touch with him at [email protected]