Home » Php » Laravel 5 / Codeception not routing correctly

Laravel 5 / Codeception not routing correctly

Posted by: admin October 29, 2017 Leave a comment

Questions:

I’m trying to write an API test case for a controller function using codeception, and I’m hitting an issue where the route to the controller function does not appear to be evaluated correctly, and the evaluation seems to be different depending on what I have in my test case.

Here is a code sample from my test case:

use \ApiTester;

class CustomerRegisterCest
{
    // tests
    public function testGetRegister(ApiTester $I)
    {
        $I->sendGET('register');
        $I->seeResponseCodeIs(200);
    }

    public function testPostRegister(ApiTester $I)
    {
        $I->sendPOST('register', [
            // set the data in here
        ]);
        $I->seeResponseCodeIs(200);
    }

I have a routes.php file containing these routes:

Route::get('/', ['as' => 'home', 'uses' => '[email protected]']);
Route::get('register', ['as' => 'getRegister', 'uses' =>'[email protected]']);
Route::post('register', ['as' => 'postRegister', 'uses' => '[email protected]']);

I have inserted some debug statements into my controller classes so that I can see what routes get run, like this:

    Log::debug('GET register');  // or GET index or POST register, etc

At the moment I have stripped down everything from my controller classes so that ONLY the debug statements are included.

When I run the test case as above, I get the following debug output:

GET register
GET index

… so it appears that sendPOST(‘register’, …) actually routes to the GET route for “/” instead of the POST route for “/register”. Outside of the test case everything works normally — I can POST to the register routes fine, routing appears to work OK, the problem only appears inside a codeception test case.

If I change the test case so that I am doing the sendGET and the sendPOST inside the same function call, for example like this:

    // tests
    public function testPostRegister(ApiTester $I)
    {
        $I->sendGET('register');
        $I->seeResponseCodeIs(200);
        $I->sendPOST('register', [
            // set the data in here
        ]);
        $I->seeResponseCodeIs(200);
    }

then I see this debug output:

GET register
GET register

… so that by inserting the sendGET into the same function as the sendPOST, it has changed the sendPOST behaviour so that it now routes to the GET route for register instead of the GET route for index (but still won’t route to the correct POST route).

I have tried turning xdebug on and don’t have any clues from the xdebug output as to what’s going on either.

Answers:

I think I found the answer after a lot of command line debugging (using phpstorm):

The POST register route handling function in the controller was declared like this:

public function postRegister(RegistrationRequest $request)
{

… requiring an instance of Request to be passed in via dependency injection. That request contained some validation code and if for some reason the validation code could not complete (e.g. throws an exception) then the controller function never gets called — because building the request fails.

This, in browser-land, throws a 500 error but in codeception land the exception is trapped differently and it returns a redirect to / with no data. This all happens outside of the controller function rather than inside it, so that the Log statement in the controller function never runs because the function never gets called. The exception handler in codeception is a generic trap.

The implicit suggestion is that maybe dependency injections in controllers are a bad idea. Or, maybe, that generic exception handlers are a bad idea.