PHPackages                             mrpunyapal/peststan - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. mrpunyapal/peststan

ActivePhpstan-extension[Testing &amp; Quality](/categories/testing)

mrpunyapal/peststan
===================

PHPStan extension for Pest PHP testing framework

0.1.5(1mo ago)291.5k↑1544.4%24MITPHPPHP ^8.2CI passing

Since Dec 28Pushed 1mo agoCompare

[ Source](https://github.com/MrPunyapal/PestStan)[ Packagist](https://packagist.org/packages/mrpunyapal/peststan)[ GitHub Sponsors](https://github.com/mrpunyapal)[ RSS](/packages/mrpunyapal-peststan/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (9)Dependencies (13)Versions (10)Used By (4)

PestStan
========

[](#peststan)

PHPStan extension for [Pest PHP](https://pestphp.com/) testing framework. Provides type-safe expectations, proper `$this` binding in test closures, and accurate return types for all Pest functions.

[![Latest Version on Packagist](https://camo.githubusercontent.com/0e091f39f03933f2efdfa6805dbc0cf7d3909ad72a3ae318972e4557810ffb1b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d7270756e796170616c2f706573747374616e2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/mrpunyapal/peststan)[![Total Downloads](https://camo.githubusercontent.com/f5dc85c0b768b59db3f2328387a868f7ab00f5798494f2a3cb605e250cfca613/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6d7270756e796170616c2f706573747374616e2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/mrpunyapal/peststan)[![CI](https://github.com/mrpunyapal/peststan/actions/workflows/ci.yml/badge.svg)](https://github.com/mrpunyapal/peststan/actions/workflows/ci.yml)

Requirements
------------

[](#requirements)

- PHP ^8.2
- PHPStan ^2.0
- Pest PHP ^3.0 or ^4.0

Installation
------------

[](#installation)

```
composer require --dev mrpunyapal/peststan
```

If you have [phpstan/extension-installer](https://github.com/phpstan/extension-installer) (recommended), the extension is registered automatically.

Otherwise, add it manually to your `phpstan.neon` or `phpstan.neon.dist`:

```
includes:
    - vendor/mrpunyapal/peststan/extension.neon
```

Features
--------

[](#features)

### Generic `expect()` Function

[](#generic-expect-function)

The extension provides generic type inference for Pest's `expect()` function, so PHPStan knows the exact type of the expectation value:

```
expect('hello');           // Expectation
expect(42);                // Expectation
expect(['a' => 1]);        // Expectation
expect($user);             // Expectation
expect();                  // Expectation
```

### Type Narrowing Assertions

[](#type-narrowing-assertions)

Type-checking assertion methods narrow the generic type parameter, so PHPStan tracks the type through assertion chains:

```
/** @var int|string $value */
$value = getValue();

expect($value)->toBeString();
// PHPStan now knows the expectation wraps a string

expect($value)->toBeInstanceOf(User::class);
// PHPStan now knows the expectation wraps a User
```

Supported type-narrowing assertions: `toBeString`, `toBeInt`, `toBeFloat`, `toBeBool`, `toBeArray`, `toBeList`, `toBeObject`, `toBeCallable`, `toBeIterable`, `toBeNumeric`, `toBeScalar`, `toBeResource`, `toBeTrue`, `toBeFalse`, `toBeNull`, `toBeInstanceOf`.

### Type-Safe `and()` Chaining

[](#type-safe-and-chaining)

The `and()` method properly changes the generic type parameter, enabling type-safe assertion chains:

```
expect('hello')
    ->toBeString()       // Expectation
    ->and(42)            // Expectation
    ->toBeInt()          // Expectation
    ->and(['a', 'b'])    // Expectation
    ->toHaveCount(2);    // Expectation
```

### `$this` Binding in Test Closures

[](#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:

```
// tests/Pest.php
uses(Tests\TestCase::class)->in('Feature');

// tests/Feature/ExampleTest.php
it('can access test case methods', function () {
    $this->get('/');  // PHPStan knows $this is Tests\TestCase
});

beforeEach(function () {
    $this->assertTrue(true);   // Works in hooks too
});
```

Supported functions: `it()`, `test()`, `describe()`, `beforeEach()`, `afterEach()`, `beforeAll()`, `afterAll()`.

### Dynamic Properties in Test Closures

[](#dynamic-properties-in-test-closures)

Pest allows setting properties on `$this` inside `beforeEach`/`beforeAll` hooks. The extension reads those assignments and **infers the exact type** — no `@var` annotation or extra local variable required:

```
beforeEach(function () {
    $this->post   = new Post;                    // Post
    $this->title  = 'Hello';                     // 'Hello' (constant string)
    $this->count  = 42;                          // 42 (constant int)
    $this->active = true;                        // true
});

it('knows the property types', function () {
    $this->post->title;          // PHPStan knows $this->post is Post — no "Cannot access property on mixed" error
    strlen($this->title);        // fine — PHPStan knows it is a string
});
```

For method-call chains such as factory calls, annotate the local variable with `@var` to guide inference:

```
beforeEach(function () {
    /** @var User $user */
    $user        = User::factory()->create();
    $this->user  = $user;        // User
});
```

If the same property is set by multiple hooks the type is **unioned**:

```
beforeEach(function () { $this->item = new Post; });
beforeEach(function () { $this->item = new Comment; });

it('sees the union', function () {
    $this->item;  // Post|Comment
});
```

Properties that are never set in a hook remain `mixed`.

Configuration
-------------

[](#configuration)

### Automatic TestCase Detection

[](#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:

```
// uses(TestCase::class)->in('Feature');
```

No configuration needed — it discovers `Pest.php` files automatically from your PHPStan `paths`.

### Manual TestCase Override

[](#manual-testcase-override)

If auto-detection doesn't work for your setup, or you want a global default, set it in your `phpstan.neon`:

```
parameters:
    peststan:
        testCaseClass: App\Testing\TestCase
```

### Explicit Pest.php Paths

[](#explicit-pestphp-paths)

If your `Pest.php` files aren't within PHPStan's analysis paths, you can specify them explicitly:

```
parameters:
    peststan:
        pestConfigFiles:
            - tests/Pest.php
```

### Pest Function Return Types

[](#pest-function-return-types)

Accurate return types for all Pest global functions:

FunctionReturn Type`expect($value)``Expectation``it()` / `test()` / `todo()``TestCall``describe()``DescribeCall`### `not()` and `each()` Return Types

[](#not-and-each-return-types)

```
expect('hello')->not();    // OppositeExpectation
expect([1, 2])->each();    // EachExpectation
```

### TestCall Chaining

[](#testcall-chaining)

All `TestCall` methods are properly typed for fluent chaining:

```
it('does something', function () { /* ... */ })
    ->with(['a', 'b'])
    ->group('unit', 'feature')
    ->skip(false)
    ->depends('other test')
    ->throws(RuntimeException::class)
    ->repeat(3);
```

### Architecture Testing Support

[](#architecture-testing-support)

Architecture testing methods are fully supported:

```
expect('App\Models')
    ->toExtend('Illuminate\Database\Eloquent\Model')
    ->ignoring('App\Models\Legacy');

expect('App')
    ->classes()
    ->toBeFinal();

expect('App\Actions')->toBeInvokable();
expect('App\DTOs')->toBeReadonly();
expect('App')->toUseStrictTypes();
```

Testing
-------

[](#testing)

```
composer test        # Run all checks (lint + types + unit)
composer lint        # Apply code style fixes (Rector + Pint)
composer test:lint   # Check code style (dry-run)
composer test:types  # Run PHPStan analysis
composer test:unit   # Run Pest unit tests
```

Contributing
------------

[](#contributing)

Contributions are welcome! Please feel free to submit a Pull Request.

License
-------

[](#license)

MIT License. See [LICENSE](LICENSE) for more information.

Credits
-------

[](#credits)

- Built for [Pest PHP](https://pestphp.com/)
- Powered by [PHPStan](https://phpstan.org/)

###  Health Score

48

—

FairBetter than 95% of packages

Maintenance90

Actively maintained with recent releases

Popularity33

Limited adoption so far

Community16

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 97.1% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~11 days

Recently: every ~1 days

Total

9

Last Release

53d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/230c58a4f918ca3e3f2988b38721230698bce88f76ae9087e4377ba0b3a074d5?d=identicon)[MrPunyapal](/maintainers/MrPunyapal)

---

Top Contributors

[![MrPunyapal](https://avatars.githubusercontent.com/u/53343069?v=4)](https://github.com/MrPunyapal "MrPunyapal (68 commits)")[![nunomaduro](https://avatars.githubusercontent.com/u/5457236?v=4)](https://github.com/nunomaduro "nunomaduro (1 commits)")[![raphaelstolt](https://avatars.githubusercontent.com/u/48225?v=4)](https://github.com/raphaelstolt "raphaelstolt (1 commits)")

---

Tags

testingpestPHPStanstatic analysis

###  Code Quality

TestsPest

Static AnalysisRector

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/mrpunyapal-peststan/health.svg)

```
[![Health](https://phpackages.com/badges/mrpunyapal-peststan/health.svg)](https://phpackages.com/packages/mrpunyapal-peststan)
```

###  Alternatives

[larastan/larastan

Larastan - Discover bugs in your code without running it. A phpstan/phpstan extension for Laravel

6.4k43.5M5.2k](/packages/larastan-larastan)[ekino/phpstan-banned-code

Detected banned code using PHPStan

2925.6M92](/packages/ekino-phpstan-banned-code)[shipmonk/dead-code-detector

Dead code detector to find unused PHP code via PHPStan extension. Can automatically remove dead PHP code. Supports libraries like Symfony, Doctrine, PHPUnit etc. Detects dead cycles. Can detect dead code that is tested.

3462.2M52](/packages/shipmonk-dead-code-detector)[szepeviktor/phpstan-wordpress

WordPress extensions for PHPStan

3287.8M898](/packages/szepeviktor-phpstan-wordpress)[staabm/phpstan-dba

2912.3M2](/packages/staabm-phpstan-dba)[staabm/phpstan-todo-by

1991.8M55](/packages/staabm-phpstan-todo-by)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
