While testing show laravel views some love

Janez Cergolj

Back in the 4.2 Laravel days, you were able to inspect views with tests more thoroughly with the help of a symphony dom crawler. Unfortunately, this feature was removed in later versions. That's a shame. As far as I know, it was replaced with a more advanced tool called Dusk, a Laravel tool for browser testing.

Laravel feature testing workflow emphasises testing request cycles. That's great. However, it has only some bare assertions for testing views. Wouldn't it be nice if you were able to assert that form is present inside view? That form has a CSRF field, has a submit button, has input fields, and validation errors are shown? Something more simple than Dusk but a bit more potent than default assertions.

After some thought, I've brought something similar from 4.2 days and, for now, more simple back to life. It is a package called Laravel view test assertions.

The easiest way to show its capabilities is to see it in action:

View

// resources/welcome.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel</title>
    </head>

    <body class="antialiased">
        <form method="post" action="/users">
            <h1>Form</h1>

            @csrf
            <input type="text" name="first_name" />
            <div>The First Name must only contain letters.</div>

            <select name="age">
                <option value="5">5 Years</option>
            </select>

            <input type="submit" value="Save" />
        </form>

        <div id="parent">
            <div class="child"></div>
        </div>

    </body>
</html>

Example Test

<?php

namespace Tests\Feature;

use Tests\TestCase;

class ExampleTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function test_example()
    {
        $response = $this->get('/');

        $response->assertStatus(200)
            ->assertViewHasForm()
            ->assertViewHasForm('post')
            ->assertViewHasForm(null, '/users')
            ->assertViewHasForm('post', '/users')
            ->assertFieldHasValidationErrorMsg(trans('validation.alpha', ['attribute' => 'First Name']))
            ->assertFormHasCSRF()
            ->assertFormHasField('text', 'first_name')
            ->assertFormHasField('select', 'age')
            ->assertFormHasDropdown('age')
            ->assertFormHasSubmitButton()
            ->assertElementHasChild('select[name="age"]', 'option[value="5"]')
            ->assertElementHasChild('select[name="age"]', 'option[plaintext="5 Years"]')
            ->assertElementHasChild('div#parent', 'div.child');
    }
}

And that's it. All those methods ensure that input fields and submit button are child elements of the form parent element and not only that they are visible inside a view. With this package, you can gain a bit more trust in views and that at least the most essential elements of the views are included and placed inside the form.