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. Save expected output (JSON, arrays, strings, etc.) on first run and automatically compare on later runs to catch regressions with minimal assertions. Includes handy traits and snapshot update workflow for tests.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require --dev spatie/phpunit-snapshot-assertions
    
  2. Basic Test Setup:

    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. The test will be marked as incomplete, and a snapshot file will be created in __snapshots__/ExampleTest__test_basic_snapshot__1.txt.


Where to Look First

  • Documentation: Focus on the README for usage patterns, assertions, and configuration.
  • Assertion Methods: Review the available methods like assertMatchesJsonSnapshot, assertMatchesHtmlSnapshot, etc., to match your testing needs.
  • Snapshot Directory: Check the __snapshots__ directory in your test folder for generated snapshots.

First Use Case

Testing API Responses:

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

Run the test once to generate the snapshot. Subsequent runs will verify the API response hasn’t changed unexpectedly.


Implementation Patterns

Usage Patterns

  1. Basic Snapshot Testing: Use assertMatchesSnapshot for simple string/text comparisons.

    $this->assertMatchesSnapshot('Hello, World!');
    
  2. Structured Data: Use format-specific assertions like assertMatchesJsonSnapshot or assertMatchesXmlSnapshot for JSON/XML responses.

    $this->assertMatchesJsonSnapshot($user->toJson());
    
  3. File Comparisons: Use assertMatchesFileHashSnapshot for quick file comparisons or assertMatchesFileSnapshot for detailed binary comparisons.

    $this->assertMatchesFileSnapshot('path/to/file.pdf');
    
  4. Image Testing: Install spatie/pixelmatch-php and use assertMatchesImageSnapshot for visual regression testing.

    $this->assertMatchesImageSnapshot('screenshot.png', 0.1);
    
  5. Named Snapshots: Use explicit IDs for clarity and easier updates.

    $this->assertMatchesJsonSnapshot($order->toJson(), 'order_response');
    

Workflows

  1. Develop-Test Cycle:

    • Write a test with a snapshot assertion.
    • Run ./vendor/bin/phpunit to generate the initial snapshot.
    • Refactor code and update snapshots with ./vendor/bin/update-snapshots when intentional changes occur.
  2. CI Integration:

    • Disable snapshot creation in CI with CREATE_SNAPSHOTS=false.
    • Use composer test:ci to fail builds on missing snapshots.
    {
        "scripts": {
            "test:ci": "CREATE_SNAPSHOTS=false vendor/bin/phpunit"
        }
    }
    
  3. Parallel Testing: Ensure CREATE_SNAPSHOTS=false is set when running tests in parallel (e.g., with Paratest or Laravel’s --parallel flag).


Integration Tips

  1. Laravel-Specific: Use snapshot testing for API responses, Blade templates, or Eloquent model outputs.

    public function test_blade_template()
    {
        $html = $this->get('/dashboard')->getContent();
        $this->assertMatchesHtmlSnapshot($html);
    }
    
  2. Custom Drivers: Extend functionality by creating custom drivers for unique data formats.

    use Spatie\Snapshots\Driver;
    
    class CustomDriver implements Driver
    {
        public function serialize($data): string { /* ... */ }
        public function extension(): string { return 'custom'; }
        public function match($expected, $actual) { /* ... */ }
    }
    
  3. Snapshot Directory Customization: Override getSnapshotDirectory to store snapshots in a project-specific location.

    protected function getSnapshotDirectory(): string
    {
        return base_path('tests/snapshots');
    }
    

Gotchas and Tips

Pitfalls

  1. Snapshot Pollution:

    • Avoid committing snapshots to version control if they’re not part of the test suite (e.g., temporary debug snapshots).
    • Use .gitignore to exclude the __snapshots__ directory or specific files.
  2. False Positives:

    • Snapshots may fail due to minor formatting changes (e.g., whitespace, line endings). Use drivers like JsonDriver with JSON_PRETTY_PRINT to normalize output.
    • For images, adjust the threshold in assertMatchesImageSnapshot to account for anti-aliasing or minor rendering differences.
  3. Parallel Testing Conflicts:

    • Ensure CREATE_SNAPSHOTS=false is set in parallel test environments to prevent snapshot file collisions.
  4. CI Failures:

    • Missing snapshots in CI will fail the build. Use CREATE_SNAPSHOTS=false to enforce this behavior intentionally.
    • Example CI script:
      CREATE_SNAPSHOTS=false phpunit
      

Debugging

  1. Failed Assertions:

    • Use assertMatchesFileSnapshot for files to generate a side-by-side comparison when tests fail.
    • For JSON/XML, inspect the diff output in the terminal to identify discrepancies.
  2. Snapshot Updates:

    • Update snapshots manually with:
      ./vendor/bin/update-snapshots tests/YourTest.php
      
    • Or via Composer:
      composer update-snapshots
      
  3. Driver Issues:

    • If a custom driver fails, verify the serialize and match methods handle edge cases (e.g., null values, non-string data).
    • Check for exceptions like CantBeSerialized and handle them gracefully.

Tips

  1. Snapshot Naming: Use descriptive IDs for named snapshots to avoid ambiguity.

    $this->assertMatchesJsonSnapshot($user->toJson(), 'user_profile_api_response');
    
  2. Exclude Snapshots: Skip specific tests during snapshot updates:

    ./vendor/bin/update-snapshots --exclude-group=slow
    
  3. Snapshot Directory Structure: Organize snapshots by feature/module for better maintainability:

    tests/
    ├── __snapshots__/
    │   ├── auth/
    │   │   ├── LoginTest__test_login_form__1.html
    │   │   └── ...
    │   └── api/
    │       ├── UserControllerTest__test_index__1.json
    │       └── ...
    
  4. Laravel Artisan: Use php artisan test --update-snapshots for Laravel projects (requires UPDATE_SNAPSHOTS=true in environment).

  5. Windows Line Endings: Configure Git to normalize line endings to avoid snapshot failures:

    git config --global core.autocrlf input
    
  6. Partial Updates: Use assertMatchesSnapshot with a subset of data to isolate changes:

    $this->assertMatchesSnapshot(json_encode(['id' => $user->id]), new JsonDriver());
    
  7. Snapshot Validation: Periodically review snapshots to remove outdated or redundant ones. Use tools like git log -- __snapshots__ to track changes.

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.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
ecotone/kafka
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata