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

Phpunit Snapshot Assertions Laravel Package

spatie/phpunit-snapshot-assertions

Add snapshot testing to PHPUnit. Assert strings, JSON, arrays, and objects against saved snapshots; first run writes snapshots, later runs compare and fail on regressions. Simple trait-based API (e.g., assertMatchesJsonSnapshot) for PHP and Laravel projects.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:
    composer require --dev spatie/phpunit-snapshot-assertions
    
  2. Basic Test Case:
    use Spatie\Snapshots\MatchesSnapshots;
    
    class ExampleTest
    {
        use MatchesSnapshots;
    
        public function test_basic_snapshot()
        {
            $this->assertMatchesSnapshot('expected output');
        }
    }
    
  3. First Run: Run ./vendor/bin/phpunit to generate the initial snapshot (test will be marked incomplete).
    ./vendor/bin/phpunit
    

First Use Case: API Response Testing

public function test_api_response()
{
    $response = $this->get('/api/users/1');
    $this->assertMatchesJsonSnapshot($response->getContent());
}

Implementation Patterns

Common Workflows

  1. JSON API Responses:

    public function test_user_profile()
    {
        $response = $this->actingAs(User::first())
            ->getJson('/api/profile');
    
        $this->assertMatchesJsonSnapshot($response->getContent());
    }
    
  2. HTML Email Templates:

    public function test_welcome_email()
    {
        $email = $this->mail->assertSent(WelcomeEmail::class)
            ->first()
            ->rendered();
    
        $this->assertMatchesHtmlSnapshot($email);
    }
    
  3. CLI Output:

    public function test_artisan_command_output()
    {
        $output = $this->artisan('command:name', ['--option' => 'value'])
            ->output();
    
        $this->assertMatchesTextSnapshot($output);
    }
    

Integration Tips

  1. Named Snapshots for Organization:

    public function test_user_serialization()
    {
        $user = User::factory()->create();
        $this->assertMatchesSnapshot($user->toArray(), 'user-serialization');
    }
    
  2. Custom Snapshot Directory:

    protected function getSnapshotDirectory(): string
    {
        return __DIR__ . '/../snapshots';
    }
    
  3. Parallel Testing:

    CREATE_SNAPSHOTS=false php artisan test --parallel
    
  4. CI Integration:

    // composer.json
    {
        "scripts": {
            "test": "php artisan test",
            "test:ci": "CREATE_SNAPSHOTS=false php artisan test"
        }
    }
    

Gotchas and Tips

Common Pitfalls

  1. Windows Line Endings:

    • Configure Git to normalize line endings:
      git config --global core.autocrlf input
      
    • Or use .gitattributes:
      __snapshots__/*.txt diff=crlf
      
  2. Binary File Snapshots:

    • Use assertMatchesFileHashSnapshot() for large files (faster, less disk space)
    • Use assertMatchesFileSnapshot() for visual comparison (slower, stores full file)
  3. Image Testing:

    • Requires spatie/pixelmatch-php:
      composer require --dev spatie/pixelmatch-php
      
    • Adjust threshold carefully (0.0-0.1 for strict, 0.2+ for lenient tests)
  4. CI False Positives:

    • Set CREATE_SNAPSHOTS=false in CI to fail on missing snapshots
    • Use UPDATE_SNAPSHOTS=true locally when intentional changes occur

Debugging Tips

  1. Snapshot Diffs:

    • Failed JSON snapshots show clear diff output
    • For text snapshots, compare manually with:
      diff __snapshots__/Test__test_method__1.txt actual_file.txt
      
  2. Custom Drivers:

    • Implement Driver interface for complex data types
    • Example for Laravel Collections:
      class CollectionDriver implements Driver
      {
          public function serialize($data): string
          {
              return json_encode($data->toArray(), JSON_PRETTY_PRINT);
          }
      
          public function extension(): string
          {
              return 'json';
          }
      
          public function match($expected, $actual)
          {
              Assert::assertEquals(json_decode($expected, true), json_decode($actual, true));
          }
      }
      
  3. Snapshot ID Conflicts:

    • Override getSnapshotId() for consistent IDs across test runs
    • Example for timestamp-based IDs:
      protected function getSnapshotId(): string
      {
          return (new ReflectionClass($this))->getShortName() .
              '__' . date('YmdHis') .
              '__' . $this->snapshotIncrementor;
      }
      

Extension Points

  1. Custom Matchers:

    $this->assertMatchesSnapshot($data, null, 'custom-matcher', function($expected, $actual) {
        return hash_equals($expected, $actual);
    });
    
  2. Pre/Post Processing:

    protected function getSnapshotId(): string
    {
        $id = parent::getSnapshotId();
        return str_replace('Test', 'Snapshot', $id);
    }
    
  3. Environment-Specific Snapshots:

    protected function getSnapshotDirectory(): string
    {
        return __DIR__ . '/../../storage/snapshots/' .
            config('app.env') . '/';
    }
    
  4. Laravel-Specific:

    • Use with Pest:
      use Spatie\Snapshots\MatchesSnapshots;
      
      it('matches snapshot', function () {
          $this->assertMatchesSnapshot('data');
      })->uses(MatchesSnapshots::class);
      
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.
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope
anil/file-picker
broqit/fields-ai