How to load routes based on application/json header in Laravel
laravel, php, phpunit, unit-testing
Solution
In my case, I was using `Content-Type` to determine which controllers to load. This didn't work for me, because routes are loaded into memory when `TestCase->createApplication()` is run. This means my headers had no effect.
I ended up making a `RouteInflector` that allows me to force my tests to use the Api routes.
class ApiTestCase extends TestCase
{
/**
* @inheritDoc
*/
public static function setUpBeforeClass()
{
/**
* Routes are loaded into memory before tests are run.
* Because of this, we can't have routing logic based on
* heads. Using the RouteInflector we can override
* header to createApplication() and must use a constant
* to force the RouteInflector to use Api controllers.
*/
RouteInflector::isJson(true);
}
public function setUp()
{
parent::setUp();
//Lets do this right
$this->client->setServerParameter('HTTP_CONTENT_TYPE', 'application/json');
$this->client->setServerParameter('HTTP_ACCEPT', 'application/json');
}
}
Inflector:
class RouteInflector
{
/** @var bool */
protected static $isJson = false;
/**
* Review the request details and determine which controller
* subpackage should be used.
* We could also check the request source to help determine the
* package.
*
* Defaults to Web.
*
* @return string
*/
public function getControllerSubpackage()
{
if (self::isJson() || Request::isJson()) {
return 'Api';
}
return 'Web';
}
/**
* Used by tests to tell routing that the current request
* is a json request.
*
* @see \Tests\ApiTestCase
*
* @param bool|null $isJson
*
* @return bool Only provided if parameter is null
*/
public static function isJson($isJson = null)
{
if (is_null($isJson)) {
return self::$isJson;
} else {
self::$isJson = $isJson;
}
}
}
Problem
I'm using the `application/json` header to control how my controller acts when a request is received. I need for the POST in my unit test to include an `application/json` header. I've tried: ``` public function testStore() { $this->validator ->shouldReceive('validate') ->once() ->with($this->attributes) ->andReturn(true); $this->repository ->shouldReceive('create') ->once() ->with($this->attributes) ->andReturn($this->entity); $this->controller ->shouldReceive('creationSucceeded') ->once() ->with($this->entity); $this->client->request('POST', 'shared/users', [], [], [ 'HTTP_CONTENT_TYPE' => 'application/json' ], json_encode($this->attributes)); $this->assertResponseStatus(201); } ``` And it the `Request::isJson()` in my controller continues to return false. I also tried using `'CONTENT_TYPE' => 'application/json'` instead of the `HTTP_CONTENT_TYPE` above.