Skip to content

fix: describe() modifier calls and arch expectation methods on internal interfaces - #13

Merged
MrPunyapal merged 2 commits into
5.xfrom
fix/describe-call-and-arch-internal-methods
Aug 21, 2026
Merged

fix: describe() modifier calls and arch expectation methods on internal interfaces#13
MrPunyapal merged 2 commits into
5.xfrom
fix/describe-call-and-arch-internal-methods

Conversation

@MrPunyapal

Copy link
Copy Markdown
Collaborator

Fixes two PHPStan false-positives reported against Pest's dynamic API.

describe() block modifiers (->skip(), ->with(), …)

At runtime, DescribeCall::__call() forwards every call to a fresh BeforeEachCall, which itself documents @mixin TestCall. That delegation was invisible to static analysis, so valid code like:

describe('user settings', function () {
    test('receives the dataset value', function (int $value) {
        expect($value)->toBeGreaterThan(0);
    });
})->with([10, 20]);

was reported as:

Call to an undefined method Pest\PendingCalls\DescribeCall::with().
🪪  method.notFound

Instead of hard-coding a method list into a reflection extension, a stub now declares the actual runtime relationship (@mixin BeforeEachCall) on DescribeCall, and PHPStan resolves modifiers through its native mixin logic. This means:

  • skip(), with(), group(), after() and chained combinations all type-check,
  • dynamically bound classes (e.g. Laravel's actingAs()) keep working through the existing TestCall extension,
  • future methods added to TestCall / BeforeEachCall are picked up automatically — nothing to maintain.

Methods of @internal arch interfaces

Pest\Arch\Contracts\ArchExpectation is marked @internal upstream while being the documented public surface of architecture testing. With PHPStan's internalTag feature toggle (part of bleeding edge), documented chains such as:

arch()->expect('App\Models')
    ->toOnlyBeUsedIn('App\Repositories')
    ->ignoring('App\Models\User');

were reported as:

Call to method ignoring() of internal interface Pest\Arch\Contracts\ArchExpectation from outside its root namespace Pest.
🪪  method.internalInterface

The suppression extension already covered method.internalClass, method.internalTrait, and property.internalClass; it now also covers method.internalInterface for receivers typed as Pest\*.

Testing

  • tests/Rules/DescribeCallMethodTest.php: covers ->skip(), ->with(), chained modifiers, and ->after() on describe blocks.
  • tests/Rules/PestInternalClassAccessIgnoreExtensionTest.php: runs with featureToggles.internalTag: true so the regression genuinely exercises the previously failing path.

Fixes pestphp/pest#1837 and fixes pestphp/pest#1831

@MrPunyapal
MrPunyapal merged commit 178079a into 5.x Aug 21, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant