1

I am returning a View from a controller's method as follows:

return view('Main::pages.content-page', compact('content'));

View renders correctly however, when I dd the response object I see that the attribute "original" of the response object is a string whereas it should have been the View Object.

Response {#385 ▼
    +original: """
    <!DOCTYPE html>\n
    <html lang="en">\n
        <head>\n
        <meta charset="utf-8">\n
        <meta http-equiv="X-UA-Compatible" content="IE=edge">\n
        <meta name="viewport" content="width=device-width, initial-scale=1">\n
        <meta name="author" content="">\n
        <meta name="csrf-token" content="2CQirHnZ7isCBRfkhOYkzPAWOzNIqJISrbb1mfDv">\n
        <meta name="description" content="">\n
        <meta name="keywords" content="">\n
          <title id="page_title">    D&eacute;couvrir\n </title>\n
        .........

Is this expected behavior because my tests are actually failing because of it, since in my test am essentially doing

$this->get(route('main.page', ['content' => $content->slug]))
     ->assertResponseOk()
     ->assertViewHas('content', $content);

Am getting the following failure

F                                                                   1 / 1 (100%)

Time: 179 ms, Memory: 20.00MB

There was 1 failure:

1) IndexControllerTest::testGetPageMethod
The response was not a view.
Failed asserting that false is true.

Looking at the structure of the assertViewHas() method we can see why

/**
 * Assert that the response view has a given piece of bound data.
 *
 * @param  string|array  $key
 * @param  mixed  $value
 * @return $this
 */
public function assertViewHas($key, $value = null)
{
    if (is_array($key)) {
        return $this->assertViewHasAll($key);
    }

    if (! isset($this->response->original) || ! $this->response->original instanceof View) {
        return PHPUnit::assertTrue(false, 'The response was not a view.');
    }
    ......

The condition ! $this->response->original instanceof View fails because original is a string but should have been a View Object.

So am at a lost here. Is this expected behavior if so why the condition in the assertViewHas method ?

I am on Laravel Homestead version '3.0.2'
Laravel 5.2.45
  • [View implements `__toString()`](https://laravel.com/api/4.2/Illuminate/View/View.html#method___toString). I don't know if this is the reason, but it's worth checking whether Laravel uses the View in a string context which calls this. – Gordon Oct 02 '16 at 07:27
  • implements __toString() as way to convert the view to string. Its default its view object. You should check that your view is correctly templated as a blade template – Aschab Oct 02 '16 at 07:31
  • Yes View implements __toString() but the Response Object should only cast the View to string and set it to it's "content" attribute, The attribute "original" of the Response object should always be the original view object. – Percy Mamedy Oct 02 '16 at 16:28

2 Answers2

2

I ran into this same issue. In my case it turned out that the response was receiving a View object when it was prepared, but one of the "after" middleware classes that touched the response before it was returned was converting the View object into a string.

Are you using the genealabs/laravel-caffeine package by chance? It was that middleware that caused my problem. By setting up that package to not be registered in the testing environment I was able to solve the problem.

0

I ran into the same issue. I could make the response return as a View when I removed an @if/@endif-clause from my Blade template.

Similar to Ryan Durham's answer, the problem was a middleware package for me as well.

Try thinking of what middleware you might have running, most likely injected by dependencies. In my case it was beyondcode/laravel-query-detector. Finding the offending middleware might take some searching and trial-and-error. If there is an easy way to find all active middleware 'in-transit', I would love to know!

The solution is to find the offending middleware class and add the following to the setUp method of your TestCase class so it looks like this:

protected function setUp(): void
{
    parent::setUp();

    $this->withoutMiddleware([OffendingMiddleware::class]);

    // …
}

This prevents the middleware from being loaded in any test case that extends your TestCase class, which should be all of them.

This answer is still relevant for Laravel 9 as of writing.

pindab0ter
  • 13
  • 4