Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

bashy's avatar
Level 65

PHPUnit throwing $errors undefined

PHPUnit error. Just submitting a form with it

exception 'ErrorException' with message 'Undefined variable: errors' in /Users/ben/Sites/projects/laravel/storage/framework/views/6881477b204dc4f1b9ef4ea57a7c09ab:30

View line 30

<div class="form-group row{{ ($errors->has('heading') ? ' has-danger' : '') }}">

I've had a search but nothing really solid on why or how to get around it. Anyone have any ideas?

Maybe this... why do we have to use @if etc... https://laracasts.com/discuss/channels/testing/in-form-submit-testing-undefined-variable-errors

0 likes
11 replies
pmall's avatar

Not sure but are you using WithoutMiddleware ? It disable session, so maybe thats why $error is not populated.

bashy's avatar
Level 65

@pmall Yeah using WithoutMiddleware. So if I remove that, I'll have to send _token with each form send. Best way to do that?

pmall's avatar

@bobbybouwmann because the session driver is set to array in testing env so the token is refreshed on each request.

When using WithoutMiddleware you can activate only the session middleware with this setup method :

public function setUp()
{
    parent::setUp();

    $kernel = app('Illuminate\Contracts\Http\Kernel');
    $kernel->pushMiddleware('Illuminate\Session\Middleware\StartSession');
}
bashy's avatar
Level 65

@bobbybouwmann Yeah can't get the token to send.

@pmall Interesting. I think I will opt for doing this though. Thanks for the guidance for including the session part though.

/**
 * Override to disable validation when testing.
 *
 * @param \Illuminate\Http\Request $request
 * @return bool
 */
protected function tokensMatch($request)
{
    if (env('APP_ENV') === 'testing') {
        return true;
    }

    return parent::tokensMatch($request);
}
ifpingram's avatar

Is it not this middleware you need to enable as well?

$kernel->pushMiddleware(\Illuminate\View\Middleware\ShareErrorsFromSession::class);
ifpingram's avatar

To be honest, I am not sure it will :(

I have just tried to get this running locally on a test environment but can't seem to be able to swap out the Kernel in any way. Although the Testing library only fakes an HTTP request, for some reason, even if I swap out the Kernel before with just the middleware I need, then it re-instantiates the full Kernel after. I've tried everything I can think of:

  • creating partial Mocks of the Kernel using just the middleware I want.
  • binding this partial Mock into container
  • replacing instance in container with this partial mock

Everything goes well until I the test. Here's my code with a load of testing bits commented:

<?php

use Illuminate\Contracts\Http\Kernel;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\WithoutMiddleware;

class ExampleTest extends TestCase
{
    use DatabaseMigrations;
    use WithoutMiddleware;

    public function setUp()
    {
        parent::setUp();

        $kernel = app(Kernel::class);
        $kernel->pushMiddleware(\Illuminate\Session\Middleware\StartSession::class);
        $kernel->pushMiddleware(\Illuminate\View\Middleware\ShareErrorsFromSession::class);
    }

    /**
     * A basic functional test example.
     *
     * @return void
     */
    public function testBasicExample()
    {
//        $mock = \Mockery::mock('MyClass')->makePartial();
//        $kernel = Mockery::mock(New \App\Http\Kernel(new Application, new \Illuminate\Routing\Router));
//        $kernel->middleware = [
//            \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
//            \App\Http\Middleware\EncryptCookies::class,
//            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
//            \Illuminate\Session\Middleware\StartSession::class,
//            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
//            //\App\Http\Middleware\VerifyCsrfToken::class,
//        ];
//
//        $this->app->instance(Kernel::class, $kernel);
//        $this->app->singleton(Kernel::class, $kernel);
//
//        dd(app(Kernel::class)); // This shows the Kernel is swapped out, but at some point below is is re-swapped out...

        $this->visit('/')
        ->see('Laravel 5');
    }
}

Please note; I've given up with the commented code, so it doesn't work if uncommented. It's more just a scratch pad of ideas I tried..

ifpingram's avatar
Level 4

Right, it seems I was leading myself up the garden path there. The thing to do to avoid all this, is to continue to use the Middleware and then swap out the middleware you wish not to use with a dummy middleware that always passes.

namespace App\Http\Middleware;

use Closure;

class DummyMiddleware
{
    public function handle($request, Closure $next)
    {
        return $next($request);
    }
}

And within the test, swap out the VerifyCsrfToken middleware with:

$this->app->instance(\App\Http\Middleware\VerifyCsrfToken::class, new DummyMiddleware());

Thanks to @adamwathan" target="_blank">https://laracasts.com/@adamwathan for this tip.

Good luck!

bashy's avatar
Level 65

@ifpingram That's a good tip. I opted for using the Middlewares since I required them for permission/role tests.

Please or to participate in this conversation.