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

Technical Evaluation

Architecture Fit

  • Snapshot Testing Paradigm: The package aligns well with Laravel’s test-driven development (TDD) and behavior-driven development (BDD) workflows, particularly for testing complex outputs (API responses, HTML, JSON, etc.). It complements Laravel’s existing testing tools (e.g., Pest, PHPUnit) without disrupting the ecosystem.
  • Laravel-Specific Use Cases: Ideal for testing:
    • API responses (e.g., Route::json() or Http::get()).
    • Blade templates/HTML output (e.g., Stringable or View responses).
    • Database snapshots (e.g., serialized Eloquent models or query results).
    • CLI commands or Artisan output.
  • Non-Laravel Compatibility: Works seamlessly in vanilla PHP/PHPUnit projects, making it versatile for monorepos or shared libraries.

Integration Feasibility

  • Minimal Boilerplate: Requires only:
    • Composer dependency (spatie/phpunit-snapshot-assertions).
    • Trait import (use Spatie\Snapshots\MatchesSnapshots).
    • Assertion methods (e.g., assertMatchesJsonSnapshot()).
  • PHPUnit Integration: Leverages PHPUnit’s existing infrastructure (test suites, parallelization, CI hooks). No custom test runners or plugins needed.
  • Driver Flexibility: Supports custom drivers for niche formats (e.g., XML, YAML, or domain-specific serializers). Example:
    $this->assertMatchesSnapshot($model->toArray(), new CustomDriver());
    

Technical Risk

  • Snapshot Bloat: Large snapshots (e.g., HTML/PDF) may clutter version control. Mitigate with:
    • .gitignore for __snapshots__/ (add to CI exclusion lists).
    • Named snapshots to avoid auto-incremented IDs.
  • False Positives: Minor formatting changes (e.g., JSON whitespace) may trigger failures. Use JsonDriver with JSON_PRETTY_PRINT to normalize output.
  • CI Complexity: Requires environment variables (CREATE_SNAPSHOTS, UPDATE_SNAPSHOTS) for CI/CD pipelines. Example:
    # GitHub Actions
    jobs:
      test:
        env:
          CREATE_SNAPSHOTS: false
    
  • Parallel Testing: Snapshots must be disabled (CREATE_SNAPSHOTS=false) to avoid race conditions in parallel test runners (e.g., Laravel’s --parallel or Paratest).

Key Questions

  1. Scope of Snapshots:
    • Should snapshots cover all test outputs (risk: brittle tests) or only critical paths (e.g., API contracts)?
    • Example: Exclude assertMatchesHtmlSnapshot() for dynamic content like timestamps.
  2. Snapshot Storage:
    • Should snapshots be version-controlled (e.g., Git) or excluded (e.g., .gitignore)?
    • Tradeoff: Excluding snapshots loses historical context but reduces noise.
  3. Update Workflow:
    • How will snapshot updates be handled in CI? Options:
      • Manual approval (e.g., require UPDATE_SNAPSHOTS=true in PRs).
      • Automated updates (e.g., composer update-snapshots in CI).
  4. Driver Customization:
    • Are existing drivers (JsonDriver, HtmlDriver) sufficient, or are custom drivers needed for domain-specific formats?
  5. Performance:
    • Will snapshot comparisons add significant overhead? Benchmark with large payloads (e.g., paginated API responses).

Integration Approach

Stack Fit

  • Laravel Ecosystem:
    • Pest Framework: Native support via uses(Spatie\Snapshots\MatchesSnapshots).
    • API Testing: Pair with Http::fake() or Route::json() to snapshot responses.
    • Artisan/CLI: Test command output with assertMatchesTextSnapshot().
    • Database: Serialize Eloquent collections or query results:
      $this->assertMatchesJsonSnapshot(Order::all()->toJson());
      
  • Non-Laravel PHP:
    • Works identically in Symfony, Lumen, or standalone PHPUnit projects.
    • Example: Snapshot Symfony controller responses:
      $response = $this->client->get('/api/orders');
      $this->assertMatchesJsonSnapshot($response->getContent());
      

Migration Path

  1. Pilot Phase:
    • Start with one test suite (e.g., API endpoints) to validate the approach.
    • Use named snapshots (e.g., assertMatchesJsonSnapshot($response, 'orders-index')) for clarity.
  2. Incremental Adoption:
    • Replace unit tests with snapshots for complex logic (e.g., data transformations).
    • Replace integration tests for API contracts or HTML rendering.
    • Avoid snapshotting dynamic data (e.g., timestamps, user-specific content).
  3. Tooling Integration:
    • Add Composer scripts for snapshot management:
      {
        "scripts": {
          "test": "phpunit",
          "update-snapshots": "UPDATE_SNAPSHOTS=true phpunit",
          "test:ci": "CREATE_SNAPSHOTS=false phpunit"
        }
      }
      
    • Configure CI to fail on missing snapshots (e.g., GitHub Actions):
      - run: composer test:ci
      

Compatibility

  • PHPUnit Versions: Supports PHPUnit 9+ (tested up to PHPUnit 12+). No breaking changes in recent releases.
  • Laravel Versions: Compatible with Laravel 8+ (PHP 8.0+). No framework-specific dependencies.
  • Parallel Testing: Requires CREATE_SNAPSHOTS=false to avoid conflicts. Example for Laravel:
    CREATE_SNAPSHOTS=false php artisan test --parallel
    
  • Windows Line Endings: Snapshots may fail due to CRLF/LF differences. Mitigate with:
    protected function getSnapshotId(): string {
        return str_replace(["\r\n", "\r"], "\n", parent::getSnapshotId());
    }
    

Sequencing

  1. Initial Setup:
    • Install the package:
      composer require --dev spatie/phpunit-snapshot-assertions
      
    • Add a test case with a snapshot assertion:
      use Spatie\Snapshots\MatchesSnapshots;
      
      class OrderTest {
          use MatchesSnapshots;
      
          public function test_index_returns_json() {
              $response = $this->getJson('/api/orders');
              $this->assertMatchesJsonSnapshot($response->getContent());
          }
      }
      
    • Run tests to generate snapshots:
      phpunit
      
  2. CI Configuration:
    • Disable snapshot creation in CI:
      CREATE_SNAPSHOTS=false phpunit
      
    • Add a manual update step for developers:
      composer update-snapshots
      
  3. Refinement:
    • Customize snapshot IDs/directories if needed:
      protected function getSnapshotDirectory(): string {
          return __DIR__ . '/../snapshots';
      }
      
    • Add custom drivers for unsupported formats.

Operational Impact

Maintenance

  • Snapshot Updates:
    • Manual: Requires developer action (composer update-snapshots or UPDATE_SNAPSHOTS=true phpunit).
    • Automated: Can be triggered in CI (e.g., on main branch), but risks masking bugs.
    • Best Practice: Use feature flags or PR approval for snapshot updates to prevent accidental merges.
  • Cleanup:
    • Orphaned snapshots (from deleted tests) may linger. Add a script to prune them:
      find __snapshots__ -type f -not -path "*/__snapshots__/*" -delete
      
  • Driver Maintenance:
    • Custom drivers require updates if serialization logic changes (e.g., JSON schema evolution).

Support

  • Debugging Failures:
    • Snapshots provide diff-like output for failures, but complex payloads (e.g., nested JSON) may need manual inspection.
    • Use assertMatchesFileSnapshot() for binary files (e.g., PDFs) to compare side-by-side.
  • Onboarding:
    • Document snapshot update workflows (e.g., "How to regenerate snapshots in CI").
    • Example doc snippet:
      ## Snapshots
      To update snapshots:
      1. Run `composer update-snapshots`.
      2. Commit the changes with a message like "chore: update snapshots".
      
  • Tooling Support:
    • Integrate with IDE plugins (e.g., PHPStorm’s PHPUnit runner) for snapshot updates.
    • Add pre-commit hooks to validate snapshots (e.g., fail if CREATE_SNAPSHOTS=false is unset).

Scaling

  • Snapshot Volume:
    • Risk: Hundreds of snapshots may slow down test suites
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.
hamzi/corewatch
minionfactory/raw-hydrator
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