Download the PHP package mrpunyapal/peststan without Composer
On this page you can find all versions of the php package mrpunyapal/peststan. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download mrpunyapal/peststan
More information about mrpunyapal/peststan
Files in mrpunyapal/peststan
Package peststan
Short Description PHPStan extension for Pest PHP testing framework
License MIT
Informations about the package peststan
Check official PHPStan plugin
PestStan
PHPStan extension for Pest PHP testing framework. Provides type-safe expectations, proper $this binding in test closures, and accurate return types for all Pest functions.
Requirements
- PHP ^8.2
- PHPStan ^2.0
- Pest PHP ^3.0, ^4.0, or ^5.0
Installation
If you have phpstan/extension-installer (recommended), the extension is registered automatically.
Otherwise, add it manually to your phpstan.neon or phpstan.neon.dist:
Features
Generic expect() Function
The extension provides generic type inference for Pest's expect() function, so PHPStan knows the exact type of the expectation value:
Type Narrowing Assertions
Type-checking assertion methods narrow the generic type parameter, so PHPStan tracks the type through assertion chains:
Supported type-narrowing assertions:
toBeString, toBeInt, toBeFloat, toBeBool, toBeArray, toBeList, toBeObject, toBeCallable, toBeIterable, toBeNumeric, toBeScalar, toBeResource, toBeTrue, toBeFalse, toBeNull, toBeInstanceOf.
Type-Safe and() Chaining
The and() method properly changes the generic type parameter, enabling type-safe assertion chains:
$this Binding in Test Closures
The extension ensures $this is properly typed inside all Pest test closures and lifecycle hooks. It auto-detects your TestCase class from your Pest.php configuration file:
Supported functions: it(), test(), describe(), beforeEach(), afterEach(), beforeAll(), afterAll().
Dynamic Properties in Test Closures
Pest allows setting properties on $this inside beforeEach hooks. The extension reads those assignments and infers the exact type — no @var annotation or extra local variable required:
For method-call chains such as factory calls, annotate the local variable with @var to guide inference:
If the same property is set by multiple hooks the type is unioned:
Properties that are never set in a hook remain mixed.
Configuration
Automatic TestCase Detection
PestStan reads your Pest.php files to determine which TestCase class is used in each test directory. It supports the uses() pattern:
No configuration needed — it discovers Pest.php files automatically from your PHPStan paths.
Manual TestCase Override
If auto-detection doesn't work for your setup, or you want a global default, set it in your phpstan.neon:
Explicit Pest.php Paths
If your Pest.php files aren't within PHPStan's analysis paths, you can specify them explicitly:
Pest Function Return Types
Accurate return types for Pest's core global functions, plus newer helpers when they exist in the installed Pest version:
| Function | Return Type |
|---|---|
expect($value) |
Expectation<TValue> |
pest() |
Configuration |
uses(...) |
UsesCall |
it() / test() / todo() |
TestCall |
describe() |
DescribeCall |
beforeEach() |
BeforeEachCall |
afterEach() |
AfterEachCall |
fixture() |
string when available |
beforeAll() / afterAll() |
null |
dataset() / covers() / mutates() |
null |
not() and each() Return Types
TestCall Chaining
All TestCall methods are properly typed for fluent chaining:
When you set peststan.testCaseClass to a custom class, PestStan also exposes that class's public helper methods on TestCall chains:
Architecture Testing Support
Architecture testing methods are fully supported:
Static Analysis Rules
PestStan ships with rules that catch common Pest mistakes at static analysis time, before your tests run.
pest.test.emptyClosure — Empty test body
Detects tests whose closure contains no statements.
pest.test.staticClosure — Static test closure
Pest binds $this inside every test closure to the TestCase instance. Marking the closure static prevents that binding.
pest.lifecycle.beforeAllDisallowed / pest.lifecycle.afterAllDisallowed — Lifecycle hooks inside describe()
Pest does not support beforeAll() or afterAll() inside describe() blocks — calling them throws at runtime.
pest.execution.invalidRepeatValue — Invalid repeat() count
repeat() requires a positive integer greater than zero.
pest.test.duplicateDescription — Duplicate test description
Two tests in the same file with the same description will collide at runtime.
pest.expectation.impossible — Assertion that always fails
When the static type already makes an assertion impossible, PestStan reports it.
Covered assertions: toBeString, toBeInt, toBeFloat, toBeBool, toBeTrue, toBeFalse, toBeNull, toBeArray, toBeList, toBeObject, toBeCallable, toBeIterable, toBeNumeric, toBeScalar, toBeInstanceOf.
pest.expectation.redundant — Assertion that always passes
When the static type already guarantees an assertion will always succeed, the assertion is redundant and adds no value.
Covered assertions: toBeString, toBeInt, toBeFloat, toBeBool, toBeTrue, toBeFalse, toBeNull, toBeArray, toBeList, toBeObject, toBeCallable, toBeIterable, toBeNumeric, toBeScalar, toBeInstanceOf.
pest.expectation.requiresIterable / pest.expectation.requiresString — Incompatible value type
Some expectation methods require the value to satisfy a pre-condition.
Methods requiring an iterable: each, sequence.
Methods requiring a string: json, toStartWith, toEndWith, toBeJson, toBeDirectory, toBeFile, toBeReadableFile, toBeWritableFile, toBeReadableDirectory, toBeWritableDirectory.
pest.lifecycle.beforeAllThisUsage — $this inside beforeAll()
beforeAll() runs once in a static context before any tests in the file. $this is not available.
Use beforeEach() to run setup before each test with $this available.
pest.throws.classNotFound / pest.throws.invalidException — Invalid throws() argument
throws() accepts a class name that implements Throwable. Passing a non-existent class or a class that is not Throwable is caught at analysis time.
pest.covers.classNotFound / pest.covers.functionNotFound — Non-existent symbol in coversClass()
coversClass(), coversTrait(), and coversFunction() reference symbols by name. PestStan verifies those symbols exist.
pest.describe.withoutTests — Empty describe() block
A describe() block that contains no it() or test() calls (only hooks, or nothing at all) is likely a mistake.
pest.group.invalidName — Empty group() name
group() requires at least one non-empty, non-whitespace string argument.
Ignoring rules
All rules use PHPStan identifiers, so you can suppress them selectively in your baseline or inline:
Canonical identifiers are emitted in diagnostics and rule errors. Legacy identifiers remain resolvable through src/Diagnostics/PestDiagnosticIdentifiers.php so downstream tooling can canonicalize older baselines or stored metadata safely.
Semantic Architecture
PestStan stays on the analysis side of the ecosystem boundary. src/Analysis/Expectation/ExpectationTypeNarrower.php applies conservative type narrowing without speculative inference.
Diagnostics are the interoperability contract surface. src/Diagnostics/PestDiagnosticIdentifiers.php resolves legacy aliases to the canonical taxonomy.
The boundary with rector-pest is intentional: PestStan reports stable semantic facts, while Rector consumes those facts to decide whether an automated remediation is safe. PestStan does not apply fixes; it provides deterministic identifiers, semantic codes, matcher categories, and type reasoning that other tools can consume.
Testing
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT License. See LICENSE for more information.