Browser Testing Your Forms with Laravel Dusk

| Posted by Shaun.Wheatcroft

With the introduction of Laravel 5.4 comes Laravel Dusk, an automated browser testing tool. Laravel Dusk allows us to generate browser tests with our favourite unit testing tool PHPUnit.

Manually testing forms to ensure they work as we expect is very time consuming and laborious, so having a unit test to automate this process is a godsend.

A simple contact form (found on nearly every website) is a good example of a form that we can generate a unit test for.

To get started I mocked up a basic form with name, email, phone and message field. I then created the route to display the form and added a simple ajax request to submit it. I then added a second route to validate the post data and return a JSON response that can be used to display the success/error message.

Now we have something to test, we can get started with Laravel Dusk.

The official documentation here contains an excellent introduction to getting started.

In this particular case, I wanted to ensure that the form is correctly submitted and passes the validation. To do this I created a new test called "it_passes_validation" and filled out all the required fields. Finally I instructed Dusk to submit the form and look for the correct response message. The test can be seen below.

/** @test */
public function it_passes_validation()
{
 $this->browse(function ($browser) {
 $browser->visit('/')
    ->type('name', 'Test')
    ->type('email', 'test@test.com')
    ->type('phone', '123456789')
    ->type('message', 'This is a test message.')
    ->press('.submit')
    ->assertSee('Your message has been sent');
 });
}

If all goes well, we should see the test pass:

There are many ways to check the result after it has been submitted, the easiest in this case was to check the page for the success message, but I could have looked for other signs. Such as, seeing if we were redirected to success page or an input had been updated with a success value. It really depends on the way the form reacts to submissions and every website seems to handle it differently.

If the form were to redirect to a success page, we could modify the test to assert the 'path' of the page, like so:

/** @test */
public function it_passes_validation()
{
 $this->browse(function ($browser) {
 $browser->visit('/')
    ->type('name', 'Test')
    ->type('email', 'test@test.com')
    ->type('phone', '123456789')
    ->type('message', 'This is a test message.')
    ->press('.submit')
    ->assertPath('/success');
 });
}

I also wanted to test an invalid form entry to ensure that when a user forgot to fill out a required field the correct validation response was returned.

To do this I created a new test and updated the function to exclude typing out the name field. I would expect the form response to be 'The name field is required', so I updated the assertion to match.

/** @test */
public function it_returns_name_validation_error()
{
 $this->browse(function ($browser) {
 $browser->visit('/')
    ->type('email', 'test@test.com')
    ->type('phone', '123456789')
    ->type('message', 'This is a test message.')
    ->press('.submit')
    ->assertSee('The name field is required');
 });
}

To validate all the fields, we can just assert that we see the correct response for each required field. E.g.

 /** @test */
    public function it_returns_all_validation_errors()
    {
        $this->browse(function ($browser) {
            $browser->visit('/')
                ->press('.submit')
                ->assertSee('The name field is required')
                ->assertSee('The email field is required')
                ->assertSee('The phone field is required')
                ->assertSee('The message field is required');
        });
    }</p>
<p>

Now if we run php unit, we should see 2 tests and 5 asserts:

Incidentally, if the form validation did not return the correct response we would see the test fail and the following message. In this example the name validation message was not returned:

We could then look at the code for the validation for the name field and see why it was not returned.

That's the essentials for testing forms with Laravel Dusk. As you can see it's relatively simple to create and is a huge time saver compared to manually testing a form.