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 Plugin Snapshots Laravel Package

spatie/pest-plugin-snapshots

Adds snapshot testing to Pest via Spatie’s snapshot assertions. Compare strings or JSON against stored snapshots with helper functions or Pest expectations. Ideal for stable output/regression testing in PHP projects.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:

    composer require spatie/pest-plugin-snapshots --dev
    

    Ensure your pest.php config includes the plugin (auto-loaded by default in Pest v2+).

  2. First test case:

    use function Spatie\Snapshots\assertMatchesSnapshot;
    
    it('matches a simple string snapshot', function () {
        $output = 'Hello, World!';
        assertMatchesSnapshot($output);
    });
    

    Run the test—it will generate a snapshot file in tests/Snapshots/ if missing.

  3. Key directories:

    • Snapshots: tests/Snapshots/ (auto-created on first run).
    • Config: None required (uses defaults).

First Use Case: API Response Testing

it('returns a valid user response', function () {
    $response = $this->getJson('/api/users/1');
    expect($response->json())->toMatchJsonSnapshot();
});

Why start here?

  • API responses are high-churn, dynamic outputs where manual assertions fail often.
  • Snapshots capture entire JSON structures without verbose assertArraySubset() calls.
  • Works seamlessly with Laravel’s Http\Testing\Concerns\InteractsWithHttpResponse.

Implementation Patterns

Core Workflows

1. Basic Snapshot Testing

// String/HTML snapshots
expect($html)->toMatchSnapshot();

// JSON snapshots (preferred for APIs)
expect($response->json())->toMatchJsonSnapshot();

// Image snapshots (e.g., PDFs, canvas)
expect($image)->toMatchImageSnapshot();

2. Dynamic Data Handling

Problem: Snapshots fail due to timestamps, IDs, or non-deterministic data. Solution: Use snapshot modifiers (from phpunit-snapshot-assertions):

expect($response->json())
    ->toMatchJsonSnapshot()
    ->withModifiers(['replaceNonDeterministicData']);

3. Grouped Snapshots

Organize snapshots by test file or dataset (e.g., UserSnapshotTest.php):

// Auto-names snapshot: `tests/Snapshots/UserSnapshotTest/it_should_return_a_valid_user_response.json`
it('returns a valid user response', function () {
    expect($response->json())->toMatchJsonSnapshot();
});

4. Expectation vs. Assertion Style

// Expectation (fluent, Pest-native)
expect($output)->toMatchSnapshot();

// Assertion (functional, explicit)
assertMatchesSnapshot($output);

When to use which?

  • Use expectations for Pest’s fluent syntax and it() blocks.
  • Use assertions in beforeEach or setup logic where expect() isn’t idiomatic.

Integration Tips

Laravel-Specific Patterns

  1. Blade/Email Testing:

    it('renders the welcome email', function () {
        $mailable = new WelcomeEmail($user);
        expect($mailable->render())
            ->toMatchSnapshot()
            ->withOptions(['ignoreWhitespace' => true]);
    });
    
  2. Livewire/Inertia Components:

    it('renders the dashboard component', function () {
        $component = new Dashboard;
        expect($component->render())
            ->toMatchSnapshot();
    });
    
  3. API Feature Testing:

    beforeEach(function () {
        $this->actingAs($user);
    });
    
    it('lists paginated users', function () {
        expect($this->getJson('/api/users')->json())
            ->toMatchJsonSnapshot();
    });
    

CI/CD Integration

  • Update snapshots on purpose:

    ./vendor/bin/pest --update-snapshots
    

    Add to a pre-release script or manual step in your workflow.

  • Visual diffs in PRs: Configure GitHub/GitLab to show snapshot diffs (see phpunit-snapshot-assertions docs).

  • Snapshot validation in CI:

    # .github/workflows/tests.yml
    jobs:
      test:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - run: composer install
          - run: ./vendor/bin/pest
    

Team Collaboration

  • Snapshot naming conventions: Use descriptive test names (e.g., it_should_render_dashboard_with_orders). Avoid generic names like it_should_work.

  • Snapshot ownership: Assign specific files/directories to teams (e.g., tests/Snapshots/API/ for backend, tests/Snapshots/Blade/ for frontend).

  • Snapshot reviews: Require snapshot updates to be reviewed in PRs (treat them as test changes).


Gotchas and Tips

Pitfalls and Debugging

1. Snapshot ID Conflicts

Issue: Duplicate snapshot IDs (fixed in v2.3.1) cause tests to fail with unclear errors. Fix:

  • Update the package:
    composer update spatie/pest-plugin-snapshots
    
  • Workaround: Delete tests/Snapshots/ and rerun tests to regenerate IDs.

2. Non-Deterministic Data

Issue: Snapshots fail due to timestamps, UUIDs, or environment-specific values (e.g., URLs). Solutions:

  • Use modifiers:
    expect($response->json())
        ->toMatchJsonSnapshot()
        ->withModifiers(['replaceNonDeterministicData']);
    
  • Preprocess data:
    $json = json_decode($response->getContent(), true);
    $json['created_at'] = '{{NON_DETERMINISTIC}}';
    expect($json)->toMatchJsonSnapshot();
    

3. Large Snapshots

Issue: Giant JSON/XML snapshots slow down tests or bloat the repo. Fix:

  • Split snapshots: Test smaller subsets (e.g., data vs. meta in API responses).
  • Use ignoreKeys:
    expect($response->json())
        ->toMatchJsonSnapshot()
        ->withOptions(['ignoreKeys' => ['pagination', 'links']]);
    

4. Snapshot File Permissions

Issue: Tests fail with "Permission denied" on snapshot files. Fix:

  • Ensure tests/Snapshots/ is writable:
    mkdir -p tests/Snapshots && chmod -R 777 tests/Snapshots
    
  • Docker: Add tests/Snapshots to volume mounts.

5. Pest Plugin Conflicts

Issue: Conflicts with other Pest plugins (e.g., pest-plugin-laravel). Fix:

  • Load plugins in correct order (snapshot plugin should load early).
  • Check for namespace collisions (e.g., custom expect() extensions).

Advanced Tips

1. Custom Snapshot Directories

Override the default tests/Snapshots/ location:

// pest.php
use Spatie\Snapshots\SnapshotTestCase;

returnsTests()->uses(SnapshotTestCase::class)->in('tests/Snapshots/Custom');

2. Snapshot Metadata

Add context to snapshots (e.g., Laravel version, PHP unit):

it('renders with Laravel 10', function () {
    expect(app()->version())->toBe('10.x');
    expect($html)->toMatchSnapshot();
})->withMetadata(['laravel' => app()->version()]);

3. Image Snapshots

Test generated images/PDFs (requires spatie/phpunit-snapshot-assertions v5.3.1+):

it('generates a valid PDF', function () {
    $pdf = PDF::loadView('invoice', ['user' => $user]);
    expect($pdf->output())->toMatchImageSnapshot();
});

Tip: Use withOptions(['tolerance' => 0.1]) for minor visual differences.

4. Partial Snapshots

Test specific keys in JSON:

expect($response->json()['data'])
    ->toMatchJsonSnapshot('user_data');

Note: Uses phpunit-snapshot-assertions's assertMatchesJsonSnapshotWithName().

5. Snapshot Testing in Factories

Test factory outputs dynamically:

it('generates valid user data', function () {
    expect(User::factory()->create()->toArray())
        ->toMatchJsonSnapshot();
});

6. Debugging Failed Snapshots

  • Diff output:
    ./vendor/bin/pest --debug
    
  • Update selectively:
    ./vendor/bin/pest --update-snapshots --filter="it_should_render_dashboard"
    

7. Performance Optimization

  • Cache snapshots: Use SnapshotTestCase::setCacheDirectory() to store snapshots in memory during development.
  • Parallel tests: Snapshots
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