renatomarinho / laravel-page-speed

Package to optimize your site automatically which results in a 35%+ optimization
MIT License
2.42k stars 279 forks source link

The package breaks the Laravel assertViewHas test method #65

Closed maxalmonte14 closed 6 years ago

maxalmonte14 commented 6 years ago

I've been having a problem for some hours with the Laravel built-in assertViewHas test method when I pass a piece of data to a view and I concluded this package is the reason, the assertViewHas method was returning the message The response is not a view. so I decided make a little test in a new empty project and see the results, this is what I did.

First of all I installed Laravel and the package:

composer create-project --prefer-dist laravel/laravel example
...
composer require renatomarinho/laravel-page-speed

HomeTest.php

<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;

class HomeTest extends TestCase
{
    public function test_data_can_be_passed_to_a_view()
    {
        $response = $this->get('/');
        $response->assertStatus(200);
        $response->assertSeeText('Example page');
        $response->assertViewHas('data');
    }
}

web.php

<?php

Route::get('/', 'HomeController');

example.blade.php

<h1>Example page</h1>

HomeController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class HomeController extends Controller
{
    public function __invoke()
    {
        return view('example', ['data' => 'A random piece of data']);
    }
}

At this point if I run the command vendor/bin/phpunit --filter=test_data_can_be_passed_to_a_view everything is fine


.                                                                   1 / 1 (100%)

Time: 958 ms, Memory: 14.00MB

OK (1 test, 3 assertions)

But if I add the package middlewares to the Kernel.php file...

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    /**
     * The application's global HTTP middleware stack.
     *
     * These middleware are run during every request to your application.
     *
     * @var array
     */
    protected $middleware = [
        \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
        \App\Http\Middleware\TrustProxies::class,

        \RenatoMarinho\LaravelPageSpeed\Middleware\InlineCss::class,
        \RenatoMarinho\LaravelPageSpeed\Middleware\ElideAttributes::class,
        \RenatoMarinho\LaravelPageSpeed\Middleware\InsertDNSPrefetch::class,
        \RenatoMarinho\LaravelPageSpeed\Middleware\RemoveComments::class,
        \RenatoMarinho\LaravelPageSpeed\Middleware\TrimUrls::class,
        \RenatoMarinho\LaravelPageSpeed\Middleware\RemoveQuotes::class,
        \RenatoMarinho\LaravelPageSpeed\Middleware\CollapseWhitespace::class,
    ];

    /**
     * The application's route middleware groups.
     *
     * @var array
     */
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
            'throttle:60,1',
            'bindings',
        ],
    ];

    /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array
     */
    protected $routeMiddleware = [
        'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    ];
}

The output of the vendor/bin/phpunit --filter=test_data_can_be_passed_to_a_view is the following:

PHPUnit 6.5.5 by Sebastian Bergmann and contributors.

F                                                                   1 / 1 (100%)

Time: 867 ms, Memory: 14.00MB

There was 1 failure:

1) Tests\Feature\HomeTest::test_data_can_be_passed_to_a_view
The response is not a view.

C:\Users\Maxal\Desktop\example\vendor\laravel\framework\src\Illuminate\Foundation\Testing\TestResponse.php:613
C:\Users\Maxal\Desktop\example\vendor\laravel\framework\src\Illuminate\Foundation\Testing\TestResponse.php:558
C:\Users\Maxal\Desktop\example\tests\Feature\HomeTest.php:16

FAILURES!
Tests: 1, Assertions: 3, Failures: 1

I don't why this happens but it's happening!

I hope you will can reproduce the error, I will try to clone the repo and find the problem, for the moment I hope this help you. Greetings!

joaorobertopb commented 6 years ago

Hi @maxalmonte14!

This happens because PageSpeed modifies the original content generated by the view.

See:

//Illuminate\Foundation\Testing\TestResponse.php

protected function ensureResponseHasView()
{
    if (! isset($this->original) || ! $this->original instanceof View) {
        return PHPUnit::fail('The response is not a view.');
    }

    return $this;
}

The methods:

Call ensureResponseHasView() internally...

You can disable PageSpeed in your tests:

<!-- phpunit.xml -->

<php>
    <env name="LARAVEL_PAGE_SPEED_ENABLE" value="false"/>
</php>

Hope this helps! :smile: