mazedul's avatar
Level 17

The Mix manifest does not exist when using orchestral/testbench

Creating a custom Laravel package using the orchestral/testbench package that helps package developer to help with PHPUnit test. So, my package on a different place and not in a Laravel installation exactly. Everything works great except the mix() function that I'm using on the blade view for resources.

<script src="{{ asset(mix('js/app.js', 'vendor/trade')) }}"></script>

And, I have the following test route set in the web.php:

<?php

use Illuminate\Support\Facades\Route;

Route::get('/', function() {
    return view('trade::_layouts.app');
});

In addition, I have the following feature test in the ExampleTest.php file:

public function testBasicTest()
{
    $response = $this->get('/');

    $response->assertStatus(200);
}

When I am running phpunit I am seeing the following error:

Expected status code 200 but received 500.
Failed asserting that false is true.

After dumping the $response in the test, I see the The Mix manifest does not exist. error. After digging for an hour I found that mix() helper function is looking for the mix-manifest.json in the orchestral/testbench package located under the vendor instead of the public folder in my package.

I tried to the following in the package ServiceProvider.php but didn't work either:

$this->app->bind('path.public', function() {
    return base_path().'/../public';
});

In addition, I see the laravel/horizon package also using the mix() helper function on the layout.blade.php file as I am doing right now and it is also using the orchestral/testbench package for the test. So, how horizon package is doing the test while I can't? What is the to override mix() helper to ensure the public path is on my package public path instead of the orchestral/testbench path?

0 likes
22 replies
mazedul's avatar
Level 17

@BOBBYBOUWMANN - The mix-manifest.json file is just a standard one and there's nothing special on this. Here's the example:

{
    "/js/app.js": "/js/app.js",
    "/css/app.css": "/css/app.css"
}

On the other hand, the line .copy('public', '../../horizontest/public/vendor/horizon') from the Horizon is copying the Horizon package public directory to the Laravel installation public/vendor/horizon/ directory which I already did. This is because it takes time to always publish assets from php artisan commands whenever you make change in your resources. So, it's better to copy it in this way.

And the following is for publishing assets php artisan vendor:publish which I did too and it works fine.

public function defineAssetPublishing()
{
    $this->publishes([
        HORIZON_PATH.'/public' => public_path('vendor/horizon'),
    ], 'horizon-assets');
}

The only problem is mix() function. It's weird that even I specified the directory asset(mix('js/app.js', 'vendor/trade')), it's still not looking in my package public/mix-manifest.json. Not sure how to about fixing this. Stuck here for last 2 days :'(

mazedul's avatar
Level 17

While I am not passing CSS file name to the view, I have registered my view in service provided using the following:

private function registerResources()
{
    $this->loadViewsFrom(__DIR__ . '/../resources/views', 'trade');
}

And I am calling the view from web.php using the following:

Route::get('/', function() {
    return view('trade::_layouts.app');
});

I just saw that even if you run mix() from the ExampleTest.php and dump() it, it will still throw you the same error.

mazedul's avatar
Level 17

@BOBBYBOUWMANN - Here's what I found when debugging his.

ErrorException: file_get_contents(/Users/mazik/Documents/Repositories/trade/vendor/orchestra/testbench-core/src/Concerns/../../laravel/public/Users/mazik/Documents/Repositories/trade/tests../public//mix-manifest.json): failed to open stream: No such file or directory

mix() is looking for the mix-manifest.json file in the vendor directory.

mazedul's avatar
mazedul
OP
Best Answer
Level 17

There are two ways to override the public_path() returned path to ensure the mix() function can find the mix-manifest.json file.

  1. One would be to override the public_path() method completely to the custom package. Laravel usage if (!function_exists()) {} before declaring any function which is good as we can define our own public_path() function in our package. However, we'll need to make sure that our override function loads before the Laravel helper method and that's another topic.
  2. The easiest way would be to change the path.public from Laravel IoC Container from the particular PHPUnit test where we're having the issue.
public function testBasicTest()
{
    $this->app->instance('path.public', $packagePublicDir);

    $response = $this->get('/');

    $response->assertStatus(200);
}
bobbybouwmann's avatar

@mazedul As I understand it's only failing in your phpunit test, or also when you use the package itself?

bobbybouwmann's avatar

Mmh, I didn't get that :P

Anyway, the best option is then to override the binding in Laravel indeed. This way you have full control of your tests!

AndreaGiuseppe's avatar

Hi @mazedul I'm in the same boat as yours..

Can you please better explain the point 2 in your best answer? $this->app->instance('path.public', $packagePublicDir); how did you configure it? also, where does 'path.public' come from?

I was trying setting the local asset path only for testing purpose inside either phpunit config file or integration test case getEnvironmentSetUp for a general solution.

Thanks

mazedul's avatar
Level 17

It's been a while but I'll try to assist as much as I could. You'll need to change the Laravel public path from inside a test like the way I did in the testBasicTest() method. This will override the Laravel public path for that specific test only whenever running unit test.

path.public is the key for Laravel IoC Container that we are overriding here. $packagePublicDir is the directory for mix-manifest.json.

AndreaGiuseppe's avatar

@mazedul thank you for your time.

So,

given that my local public directory is /public.

and I have a tests folder in /tests I have an IntegrationTestCase.php inside where I setup the path of my public folder

<?php

namespace ..\Tests;

use Orchestra\Testbench\TestCase as OrchestraTestCase;

use ...ServiceProvider;

abstract class IntegrationTestCase extends OrchestraTestCase
{
    protected $path;

    //..package provider

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

        $this->loadLaravelMigrations();

        $this->path = realpath(__DIR__.'/../public'); // this point to /public
    }
}

then down in my integration tests I use $this->app->instance('path.public', $this->path); inside a test method.. but, this gives again error 500: mix manifest

How did you see the ErrorException to find out where mix is looking for the manifest.json?

mazedul's avatar
Level 17

As far as I can remember, the error exception was showing in the terminal window or I dd() it into the Laravel core mix() helper function. But, it should show into the PHPUnit test runner output window.

You can also add the $this->withoutExceptionHandling(); to make sure that you're seeing the exact exception instead of Laravel modified exception.

That said what do you see exactly if you just add a basic test like mine in a fresh test file?

public function testBasicTest()
{
    $this->app->instance('path.public', $packagePublicDir);

    $response = $this->get('/');

    $response->assertStatus(200);
}
AndreaGiuseppe's avatar
..Tests\Integration\Http\Controllers\BeveragesControllerTest::test_DisplayListOfBeverages
ErrorException: The Mix manifest does not exist. (View: C:\Users\....\resources\views\layout.blade.php) (View: C:\Users\....\resources\views\layout.blade.php)

But I'm sure I have the mix-manifest inside /public. I try with dump() inside laravel core mix() to see where it points.

Ok.. after dump() I see mix is pointing to C:\Users\...\public\/vendor/package/mix-manifest.json and clearly this is due because of: <link rel="stylesheet" href="{{ asset(mix('css/app.css', 'vendor/package')) }}" />

mazedul's avatar
Level 17

Nice, you can now simply override the public path using the $this->app->instance('path.public', $packagePublicDir); which will override it from the Laravel IoC container only for unit test.

AndreaGiuseppe's avatar

mmh.. seems a bit tricky, I'm under version control and that seems to be a special case to be managed with a specific branch and a specific commit..

if I use:

<link rel="stylesheet" href="{{ asset(mix('css/app.css')) }}" />

instead of:

<link rel="stylesheet" href="{{ asset(mix('css/app.css', 'vendor/package')) }}" />

everything good.. but in production the assets doesn't load..

how did you override your $packagePublicDir?

EKhawlah's avatar

I had the same problem, and found out that starting from laravel 6 we can use a tests helper method to disable Laravel Mix on tests

$this->withoutMix();
4 likes

Please or to participate in this conversation.