Mauro Casas
Mauro Casas

Reputation: 2445

Handling Custom Exceptions from PHPUnit (Laravel 5.2)

I'm currently playing around with Exception Handler, and creating my own custom exceptions.

I've been using PHPUnit to run tests on my Controller Resource, but when I throw my custom exceptions, Laravel thinks it's coming from a regular HTTP request rathen than AJAX.

Exceptions return different response based on wether it's an AJAX request or not, like the following:

<?php namespace Actuame\Exceptions\Castings;

use Illuminate\Http\Request;

use Exception;

use Actuame\Exceptions\ExceptionTrait;

class Already_Applied extends Exception 
{

    use ExceptionTrait;

    var $redirect = '/castings';
    var $message = 'castings.errors.already_applied';

}

And the ExceptionTrait goes as follows:

<?php

namespace Actuame\Exceptions;

trait ExceptionTrait 
{

    public function response(Request $request)
    {
        $type = $request->ajax() ? 'ajax' : 'redirect';

        return $this->$type($request);
    }

    private function ajax(Request $request)
    {
        return response()->json(array('message' => $this->message), 404);
    }

    private function redirect(Request $request)
    {
        return redirect($this->redirect)->with('error', $this->message);
    }

}

Finally, my test goes like this (excerpt of the test that's failing)

public function testApplyToCasting()
{
    $faker = Factory::create();

    $user = factory(User::class)->create();

    $this->be($user);

    $casting = factory(Casting::class)->create();

    $this->json('post', '/castings/apply/' . $casting->id, array('message' => $faker->text(200)))
        ->seeJsonStructure(array('message'));
}

My logic is like this although I don't think the error is coming from here

public function apply(Request $request, User $user)
{
    if($this->hasApplicant($user))
        throw new Already_Applied;

    $this->get()->applicants()->attach($user, array('message' => $request->message));

    event(new User_Applied_To_Casting($this->get(), $user));

    return $this;
}

When running PHPUnit, the error I get returned is

1) CastingsTest::testApplyToCasting PHPUnit_Framework_Exception: Argument #2 (No Value) of PHPUnit_Framework_Assert: :assertArrayHasKey() must be a array or ArrayAccess

/home/vagrant/Code/actuame2/vendor/laravel/framework/src/Illuminate/Foundation/T esting/Concerns/MakesHttpRequests.php:304 /home/vagrant/Code/actuame2/tests/CastingsTest.php:105

And my laravel.log is over here http://pastebin.com/ZuaRaxkL (Too large to paste)

I have actually discovered that PHPUnit is not actually sending an AJAX response, because my ExceptionTrait actually changes the response on this. When running the test it takes the request as a regular POST request, and runs the redirect() response rather than ajax(), hence it's not returning the correspond.

Thanks a bunch!

Upvotes: 0

Views: 524

Answers (1)

Mauro Casas
Mauro Casas

Reputation: 2445

I have finally found the solution!

As I said, response wasn't the right one as it was trying to redirect rathen than return a valid JSON response.

And after going through the Request code, I found out that I need to use also wantsJson(), as ajax() may not be the case always, so I have modified my trait to this:

<?php

namespace Actuame\Exceptions;

trait ExceptionTrait 
{

    public function response(Request $request)
    {
        // Below here, I added $request->wantsJson()
        $type = $request->ajax() || $request->wantsJson() ? 'ajax' : 'redirect';

        return $this->$type($request);
    }

    private function ajax(Request $request)
    {
        return response()->json(array('message' => $this->message), 404);
    }

    private function redirect(Request $request)
    {
        return redirect($this->redirect)->with('error', $this->message);
    }

}

Upvotes: 0

Related Questions