I'm trying to include unit-testing in a new Laravel app I'm building. Right now I'm want to test my OrderController. The index method of this controller looks like this:
public function index()
{
// We need the extra 'orders()' for the query scope
$orders = $this->order->orders()->paginate($this->perPage);
$this->layout->content = View::make('orders.index', compact('orders'));
}
Now I have my test that looks like this:
public function testIndex()
{
$this->call('GET', 'orders');
$this->assertResponseOk();
$this->assertViewHas('orders');
}
Now if I run phpunit, the test does run, but I'm getting: 1) OrderControllerTest::testIndex
Failed asserting that an array has the key 'orders'.
I've tracked down the issue to using Controller Layouts $this->layout.
If I just do return View::make() the test does pass, if I return $this->layout... it also does pass, but this destroys the actual app.
So only option I've found is to use return View::make() and have @extends('master') in that view. But it's seems strange to me that you can't use Controller Layouts in your app if you want to test it.
Am I doing something wrong?
Edit: I had the same problem and here is slightly messy solution that works!
View::composer('ordersviewname', function($view) {
$this->assertArrayHasKey('orders', $view->getData());
});
$this->call('GET', 'orders');
Note that you have to put this code BEFORE $this->call()
EDIT: Here is more elegant solution! Add functions to TestCase
protected $nestedViewData = array();
public function registerNestedView($view)
{
View::composer($view, function($view){
$this->nestedViewsData[$view->getName()] = $view->getData();
});
}
/**
* Assert that the given view has a given piece of bound data.
*
* @param string|array $key
* @param mixed $value
* @return void
*/
public function assertNestedViewHas($view, $key, $value = null)
{
if (is_array($key)) return $this->assertNestedViewHasAll($view, $key);
if ( ! isset($this->nestedViewsData[$view]))
{
return $this->assertTrue(false, 'The view was not called.');
}
$data = $this->nestedViewsData[$view];
if (is_null($value))
{
$this->assertArrayHasKey($key, $data);
}
else
{
if(isset($data[$key]))
$this->assertEquals($value, $data[$key]);
else
return $this->assertTrue(false, 'The View has no bound data with this key.');
}
}
/**
* Assert that the view has a given list of bound data.
*
* @param array $bindings
* @return void
*/
public function assertNestedViewHasAll($view, array $bindings)
{
foreach ($bindings as $key => $value)
{
if (is_int($key))
{
$this->assertNestedViewHas($view, $value);
}
else
{
$this->assertNestedViewHas($view, $key, $value);
}
}
}
public function assertNestedView($view)
{
$this->assertArrayHasKey($view, $this->nestedViewsData);
}
Now you would rewrite your test
$view='orders';
$this->registerNestedView($view);
$this->call('GET', 'orders');
$this->assertNestedViewHas($view, 'orders');
assertNestedViewHas() has all the same feautures as assertViewHas() !
I added another function assertNestedView() which just check if given view was called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With