Testing HTML5 Validation with Laravel Dusk

1.9k views Asked by At

I am creating a simple test inside Laravel Dusk that a user cannot register when leaving the email field blank. The test code is below:

    /** @test */
    public function a_user_cannot_register_without_filling_in_email_field()
    {
        $this->browse(function (Browser $browser) {
            $browser->visit('/register')
                ->type('password', $this->user->password)
                ->type('password_confirmation', $this->user->password)
                ->press('Register')
                ->assertSee('The email field is required.');
        });
    }

When the required attribute is removed from the form input this test passes, but when it is added the test fails.

Is there another way to test this?

3

There are 3 answers

0
Andy Holmes On BEST ANSWER

The way that I have managed to get this test to pass is to do the following:

Create a helpers.php inside the app directory. Make sure that this file is included in your autoloaders in your composer.json

"autoload": {
    "classmap": [
        "database/seeds",
        "database/factories"
    ],
    "files": [
        "app/helpers.php"
    ],
    "psr-4": {
        "App\\": "app/"
    }
},

Inside helpers.php you can create the following custom function:

<?php

/**
 * Helper to put novalidate on a form when testing
 */

function disableValidationIfTesting() {
    $env = env('APP_ENV');
    if ($env == 'local') {
        echo 'novalidate';
    } else {
        return;
    }
}

Change this to reflect your local environment name. Sometimes it can be testing but in my instance its just local.

Then, in your forms you're checking with tests add the following code to your form

{{ disableValidationIfTesting() }} - this is how you render the function in your blade file.

In my instance I have included it like this:

<form class="form-horizontal" method="POST" action="{{ route('register') }}" {{ disableValidationIfTesting() }}>

This means that when I'm developing and testing locally (as you shouldn't use dusk on a production server) the form gets a novalidate attribute added to it that allows the browser to skip the HTML5 Validation and just continue with the standard Laravel validation.

After doing this, all of my tests pass no problems :D

0
Ruben Beeftink On

I've been struggling with this as well. I don't think HTML5 validation errors are rendered in the DOM, which means dusk can't check if they are actually rendered or not. (this is because the web driver that is used by dusk ultimately uses javascript to get the elements on your website to click, get value, type, etc.)

In your case HTML5 validation is preventing your form from submitting. This means you won't see your own error message as the data is never validated by your code and thus your error message is not rendered and dusk does not see it.

In my case I've just disabled HTML5 form validation, as it was just an extra layer of nice client-side validation but ultimately not crucial.

0
Alexander Taubenkorb On

Thanks to Andy Holmes answer answer I came up with the following using script, so that only the test case modifies that and I don't have to change the original form source code.

So using $browser->script("document.querySelector('form').noValidate = true"); is the key.

<?php
/** @test */
public function a_user_cannot_register_without_filling_in_email_field()
{
    $this->browse(function (Browser $browser) {
        $browser->visit('/register')
            ->script("document.querySelector('#form_register').noValidate = true");

        $browser->type('password', $this->user->password)
            ->type('password_confirmation', $this->user->password)
            ->press('Register')
            ->assertSee('The email field is required.');
    });
}