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.
Installation:
composer require --dev spatie/phpunit-snapshot-assertions
Basic Test Setup:
use Spatie\Snapshots\MatchesSnapshots;
class ExampleTest
{
use MatchesSnapshots;
public function test_basic_snapshot()
{
$this->assertMatchesSnapshot('expected_output');
}
}
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.
assertMatchesJsonSnapshot, assertMatchesHtmlSnapshot, etc., to match your testing needs.__snapshots__ directory in your test folder for generated snapshots.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.
Basic Snapshot Testing:
Use assertMatchesSnapshot for simple string/text comparisons.
$this->assertMatchesSnapshot('Hello, World!');
Structured Data:
Use format-specific assertions like assertMatchesJsonSnapshot or assertMatchesXmlSnapshot for JSON/XML responses.
$this->assertMatchesJsonSnapshot($user->toJson());
File Comparisons:
Use assertMatchesFileHashSnapshot for quick file comparisons or assertMatchesFileSnapshot for detailed binary comparisons.
$this->assertMatchesFileSnapshot('path/to/file.pdf');
Image Testing:
Install spatie/pixelmatch-php and use assertMatchesImageSnapshot for visual regression testing.
$this->assertMatchesImageSnapshot('screenshot.png', 0.1);
Named Snapshots: Use explicit IDs for clarity and easier updates.
$this->assertMatchesJsonSnapshot($order->toJson(), 'order_response');
Develop-Test Cycle:
./vendor/bin/phpunit to generate the initial snapshot../vendor/bin/update-snapshots when intentional changes occur.CI Integration:
CREATE_SNAPSHOTS=false.composer test:ci to fail builds on missing snapshots.{
"scripts": {
"test:ci": "CREATE_SNAPSHOTS=false vendor/bin/phpunit"
}
}
Parallel Testing:
Ensure CREATE_SNAPSHOTS=false is set when running tests in parallel (e.g., with Paratest or Laravel’s --parallel flag).
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);
}
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) { /* ... */ }
}
Snapshot Directory Customization:
Override getSnapshotDirectory to store snapshots in a project-specific location.
protected function getSnapshotDirectory(): string
{
return base_path('tests/snapshots');
}
Snapshot Pollution:
.gitignore to exclude the __snapshots__ directory or specific files.False Positives:
JsonDriver with JSON_PRETTY_PRINT to normalize output.threshold in assertMatchesImageSnapshot to account for anti-aliasing or minor rendering differences.Parallel Testing Conflicts:
CREATE_SNAPSHOTS=false is set in parallel test environments to prevent snapshot file collisions.CI Failures:
CREATE_SNAPSHOTS=false to enforce this behavior intentionally.CREATE_SNAPSHOTS=false phpunit
Failed Assertions:
assertMatchesFileSnapshot for files to generate a side-by-side comparison when tests fail.Snapshot Updates:
./vendor/bin/update-snapshots tests/YourTest.php
composer update-snapshots
Driver Issues:
serialize and match methods handle edge cases (e.g., null values, non-string data).CantBeSerialized and handle them gracefully.Snapshot Naming: Use descriptive IDs for named snapshots to avoid ambiguity.
$this->assertMatchesJsonSnapshot($user->toJson(), 'user_profile_api_response');
Exclude Snapshots: Skip specific tests during snapshot updates:
./vendor/bin/update-snapshots --exclude-group=slow
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
│ └── ...
Laravel Artisan:
Use php artisan test --update-snapshots for Laravel projects (requires UPDATE_SNAPSHOTS=true in environment).
Windows Line Endings: Configure Git to normalize line endings to avoid snapshot failures:
git config --global core.autocrlf input
Partial Updates:
Use assertMatchesSnapshot with a subset of data to isolate changes:
$this->assertMatchesSnapshot(json_encode(['id' => $user->id]), new JsonDriver());
Snapshot Validation:
Periodically review snapshots to remove outdated or redundant ones. Use tools like git log -- __snapshots__ to track changes.
How can I help you explore Laravel packages today?