Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Pest Laravel Package

pestphp/pest

Pest is an elegant PHP testing framework focused on simplicity and joyful, expressive tests. Built for modern PHP projects, it offers a clean syntax, rich assertions, plugins, and great developer experience for unit, feature, and more.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require pestphp/pest --dev --with-all-dependencies
    

    For Laravel projects, Pest is pre-configured via pest.php (auto-generated in tests/).

  2. First Test: Replace tests/Feature/ExampleTest.php with:

    use App\Models\User;
    
    it('creates a user', function () {
        $user = User::factory()->create();
        expect($user->email)->toBeString();
    });
    

    Run with:

    ./vendor/bin/pest
    
  3. Key Files:

    • pest.php: Global configuration (plugins, aliases, parallelization).
    • tests/: Test files (Pest auto-discovers .php files).
    • phpunit.xml: Fallback config (rarely modified).

First Use Case: HTTP Testing

Replace a Laravel HttpTestCase with Pest’s fluent syntax:

it('returns a welcome page', function () {
    $response = $this->get('/');
    $response->assertStatus(200)
             ->assertSee('Welcome');
});

Implementation Patterns

1. Test Organization

  • File Structure:
    tests/
    ├── Unit/          # Unit tests (e.g., `UserTest.php`)
    ├── Feature/       # HTTP/API tests (e.g., `AuthTest.php`)
    ├── Browser/       # Playwright E2E tests (e.g., `CheckoutTest.php`)
    └── Pest.php       # Global config
    
  • Naming Conventions: Use it() for scenarios, describe() for grouping:
    describe('User Authentication', function () {
        it('fails with invalid credentials');
        it('redirects after login');
    });
    

2. Laravel Integration

  • Helpers:

    • actingAs(): Simulate logged-in users.
    • create(): Factory shortcuts (e.g., User::factory()->create()).
    • assertSee(), assertDontSee(): Response assertions.
    it('requires authentication', function () {
        $this->get('/dashboard')
             ->assertRedirect('/login');
    });
    
  • Service Providers: Use TestCase traits or extend PestTestCase:

    use Pest\TestCase;
    
    class UserTest extends PestTestCase {
        // Tests here
    }
    

3. Browser Testing (Playwright)

  • Setup:
    composer require pestphp/pest-plugin-browser
    
  • Example:
    it('submits a form', function () {
        $this->browse()
             ->visit('/login')
             ->fill('email', 'user@example.com')
             ->fill('password', 'secret')
             ->press('Login')
             ->assertPathIs('/dashboard');
    });
    
  • Geolocation/Timezones:
    $this->browse()->from()->newYork()->visit('/');
    

4. Architecture Testing

  • Plugin:
    composer require pestphp/pest-plugin-arch
    
  • Example:
    it('prevents controllers from calling databases directly')
        ->expect('App\Http\Controllers')
        ->not->toUse('App\Models')
        ->but->toUse('App\Services');
    

5. Parallelization

  • Config (pest.php):
    parallel()->with(4); // Run 4 parallel workers
    
  • CI Optimization: Use --parallel flag:
    ./vendor/bin/pest --parallel --workers=8
    

6. Mocking & Stubs

  • Mocking:
    $mock = $this->mock(EmailService::class);
    $mock->shouldReceive('send')->once();
    
  • Stubs:
    $this->stub(Storage::class, function ($stub) {
        $stub->shouldReceive('disk')->andReturnSelf();
        $stub->shouldReceive('put')->andReturn(true);
    });
    

7. Test Data

  • Factories:
    $user = User::factory()->create(['email' => 'test@example.com']);
    
  • Custom Data:
    $data = [
        'title' => 'Test Post',
        'body' => 'Content...',
    ];
    

8. Database Transactions

  • Auto-Rollback: Pest wraps tests in transactions by default. Disable with:
    it('uses raw SQL', function () {
        DB::beginTransaction();
        // Test logic
        DB::rollBack();
    })->withoutTransactions();
    

Gotchas and Tips

Pitfalls

  1. Playwright Browser Tests:

    • Headless Mode: Ensure PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD is unset in CI.
    • Slow Tests: Use ->waitForSelector() sparingly; prefer ->assertPathIs() for faster checks.
    • Geolocation: Cities like newYork() require intl PHP extension.
  2. Architecture Testing:

    • False Positives: Exclude third-party classes with:
      ->ignore('Vendor\\*')
      
    • Performance: Run architecture tests separately (they’re slower).
  3. Parallelization:

    • Race Conditions: Avoid static state in tests. Use beforeEach() for setup.
    • CI Limits: GitHub Actions may throttle parallel workers; use --workers=2 as a fallback.
  4. Database Testing:

    • Pending Migrations: Run php artisan migrate in beforeAll() if needed.
    • Seeding: Use DatabaseMigrationsAndSeeders::class trait or ->withSeed():
      it('uses seeded data')->withSeed();
      
  5. Assertion Quirks:

    • Floating-Point: Use expect(1.0000000001)->toBeApproximately(1, 3).
    • Collections: Chain assertions:
      expect($users)->toHaveCount(1)
                    ->first()
                    ->email->toBe('test@example.com');
      

Debugging Tips

  • Verbose Output:
    ./vendor/bin/pest --verbose
    
  • Test Isolation: Use ->withoutMocking() or ->withoutStubs() to debug mock/stub issues.
  • Browser Debugging: Add --headed to see Playwright in action (useful for visual regression testing).

Configuration Quirks

  1. pest.php Overrides:

    • Set default() to customize global behavior:
      default()
          ->in('tests/Unit')
          ->withTimer();
      
    • Use expect() to modify assertions globally:
      expect()->extend('custom', function ($actual, $expected) {
          return $actual === $expected;
      });
      
  2. Plugin Conflicts:

    • Disable plugins in pest.php:
      plugins([
          // Disable browser plugin
          // \Pest\Browser\BrowserPlugin::class,
      ]);
      
  3. CI-Specific Issues:

    • Xdebug: Disable in CI (add to .env.ci):
      XDEBUG_MODE=off
      
    • Memory Limits: Increase for large test suites:
      ./vendor/bin/pest --memory=1G
      

Extension Points

  1. Custom Assertions:

    use Pest\Expectation;
    
    Expectation::extend('isEven', function ($actual) {
        return $actual % 2 === 0;
    });
    

    Usage:

    expect(4)->toBeEven();
    
  2. Test Templates: Use pest --init to scaffold custom templates (e.g., FeatureTest.php):

    // tests/_templates/FeatureTest.php
    <?php
    use Pest\TestCase;
    
    class FeatureTest extends TestCase {
        use CreatesApplication;
        // Custom setup
    }
    
  3. Browser Customization: Override Playwright config in pest.php:

    browser()
        ->withOptions([
            'timeout' => 10000,
            'headless' => false,
        ]);
    
  4. Parallel Worker Hooks: Run code before/after parallel workers:

    parallel()
        ->before(function () {
            // Shared setup
        })
        ->after(function () {
            // Shared teardown
        });
    

Performance Tips

  • Skip Slow Tests:
    ./vendor/bin/pest --filter="slow"
    
  • Selective Running:
    ./vendor/bin/pest tests/Feature/AuthTest.php
    
  • Coverage Exclusion:
    ./vendor/bin/pest --
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport