mrpunyapal/peststan
PHPStan extension for Pest PHP. Adds generic typing for expect(), type-narrowing assertions, type-safe and() chaining, correct $this binding in test closures, and accurate return types for Pest functions. Supports Pest 3–5 on PHP 8.2+.
extension.neon, Extension classes) without requiring custom tooling. This aligns perfectly with Laravel’s reliance on PHPStan for static analysis.expect(), $this binding, dynamic properties), which is critical for Laravel projects using Pest for testing.$this typing in TestCase subclasses (e.g., Illuminate\Foundation\Testing\TestCase).composer require --dev mrpunyapal/peststan) and works with phpstan/extension-installer (already common in Laravel projects).TestCase classes (e.g., App\Tests\TestCase) via phpstan.neon, accommodating Laravel’s layered testing structure.@var annotations for accurate typing.beforeEach hooks) may need manual refinement.pest.test.emptyClosure) add noise if ignored indiscriminately. Requires tuning via phpstan.neon or baseline files.PHPStan Upgrade Readiness:
TestCase Hierarchy:
TestCase class (e.g., extending Illuminate\Foundation\Testing\TestCase)? If so, manual configuration may be needed in phpstan.neon.Rule Adoption:
pest.test.emptyClosure)?Performance Impact:
Dynamic Property Handling:
beforeEach setups (e.g., nested factories, conditional assignments) that might break type inference? If so, @var annotations may be needed.Laravel + Pest Ecosystem: PestStan is tailored for Laravel’s testing stack, addressing gaps in PHPStan’s native support for Pest. Key alignments:
expect() typing reduces runtime errors.TestCase (e.g., Illuminate\Foundation\Testing\TestCase) is automatically detected, ensuring $this-> methods (e.g., actingAs(), assertDatabaseHas()) are statically typed.toExtend('Illuminate\Database\Eloquent\Model')).Tooling Synergy:
phpstan/extension-installer, pestphp/pest-plugin, and Laravel’s phpunit.xml (if dual-testing).phpstan.neon configuration (e.g., paths, level).Prerequisite Check:
composer require --dev mrpunyapal/peststan in the project root.Configuration:
tests/Pest.php, no config is needed.phpstan.neon:
parameters:
peststan:
testCaseClass: App\Tests\TestCase
Pest.php files are outside PHPStan’s paths, list them:
parameters:
peststan:
pestConfigFiles:
- tests/Feature/Pest.php
- tests/Unit/Pest.php
Incremental Adoption:
expect($user)->toBeInstanceOf(User::class)) in critical test files.pest.test.emptyClosure) and adjust baselines as needed.@phpstan-ignore sparingly for edge cases (e.g., dynamic factories).CI/CD Integration:
- name: PHPStan
run: vendor/bin/phpstan analyse --level=max tests --configuration=phpstan.neon
phpstan.neon excludes PHPUnit test files if using both:
paths:
- tests/Unit
- tests/Feature
ignoreFiles:
- tests/PHPUnit/*.php
spatie/laravel-test-factory, nunomaduro/collision).TestCase detection and dynamic properties in a subset of tests.pest.expectation.* rules, then expand to pest.test.*.--generate-baseline and commit the baseline.phpstan.neon or baselines as needed.toBeString()").@phpstan-ignore pest.test.emptyClosure).@var hints.--parallel flag). No known bottlenecks.How can I help you explore Laravel packages today?