Great write-up! You’ve already covered the main approach for isolating compiled Blade views per parallel test process. Here’s a concise summary and a few extra tips to ensure smooth operation for anyone implementing this in Laravel 11+:
Summary of Solution:
- Replace the Default View Service Provider
In bootstrap/app.php, replace Laravel’s default ViewServiceProvider with your custom one:
->withProviders(ServiceProvider::defaultProviders()
->merge([])
->replace([\Illuminate\View\ViewServiceProvider::class => \App\Providers\ViewServiceProvider::class])
->toArray()
)
- Custom ViewServiceProvider
Extend Laravel’s provider and override the registerBladeCompiler method to bind your custom compiler:
namespace App\Providers;
use App\Services\BladeCompiler;
use Illuminate\View\DynamicComponent;
class ViewServiceProvider extends \Illuminate\View\ViewServiceProvider
{
public function registerBladeCompiler()
{
$this->app->singleton('blade.compiler', function ($app) {
return tap(new BladeCompiler(
$app['files'],
$app['config']['view.compiled'],
$app['config']->get('view.relative_hash', false) ? $app->basePath() : '',
$app['config']->get('view.cache', true),
$app['config']->get('view.compiled_extension', 'php'),
$app['config']->get('view.check_cache_timestamps', true),
), function ($blade) {
$blade->component('dynamic-component', DynamicComponent::class);
});
});
}
}
- Custom BladeCompiler
Override the compile method to set a process-specific cache path during parallel tests:
namespace App\Services;
use Illuminate\Support\Facades\ParallelTesting;
class BladeCompiler extends \Illuminate\View\Compilers\BladeCompiler
{
protected function setCachePath(false|string $token): void
{
if (is_string($token)) {
$this->cachePath = config('view.compiled') . DIRECTORY_SEPARATOR . "view_{$token}";
if (!is_dir($this->cachePath)) {
mkdir($this->cachePath, 0777, true);
}
}
}
public function compile($path = null)
{
if (app()->runningUnitTests()) {
$this->setCachePath(ParallelTesting::token());
}
return parent::compile($path);
}
}
Extra Tips:
-
Cleanup:
After your parallel tests finish, you may want to clean up the per-process view cache directories. You can do this in yourphpunit.xmlwith aprocessUncoveredFilesscript or in atearDownmethod. -
Environment Variable:
Make sureVIEW_COMPILED_PATHis set in your.env.testingto a writable directory (e.g.,storage/framework/testing/views). -
Permissions:
Ensure the created directories are writable by your test runner, especially in CI environments.
Why This Works:
Laravel’s Blade compiler caches compiled views in a single directory by default. When running tests in parallel, processes can overwrite each other's compiled files, causing random failures. By isolating the cache per process (using the process token), you eliminate this race condition.
Conclusion:
Your approach is solid and should help anyone running into flaky Blade-related errors during parallel testing. Thanks for sharing it with the community!