Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions src/Concerns/SnapshotIdAware.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,40 @@

namespace Spatie\Snapshots\Concerns;

use PHPUnit\Framework\Attributes\Before;
use ReflectionClass;

trait SnapshotIdAware
{
use PhpUnitCompatibility;

protected int $snapshotIncrementor = 0;

#[Before]
public function setUpSnapshotIncrementor()
{
$this->snapshotIncrementor = 0;
}

/*
* Determines the snapshot's id. By default, the test case's class and
* method names are used.
*
* If an explicit `$id` is provided, it will be prefixed with 's-' to
* distinguish it from auto-generated incrementor-based IDs. This avoids
* conflicts, should an explicit `$id` be numeric.
*/
protected function getSnapshotId(): string
protected function getSnapshotId(?string $id = null): string
{
if ($id !== null) {
$suffix = 's-'.$id;
} else {
$this->snapshotIncrementor++;
$suffix = $this->snapshotIncrementor;
}

return (new ReflectionClass($this))->getShortName().'__'.
$this->nameWithDataSet().'__'.
$this->snapshotIncrementor;
$suffix;
}
}
67 changes: 27 additions & 40 deletions src/MatchesSnapshots.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace Spatie\Snapshots;

use PHPUnit\Framework\Attributes\Before;
use PHPUnit\Framework\Attributes\PostCondition;
use PHPUnit\Framework\ExpectationFailedException;
use ReflectionObject;
Expand All @@ -23,17 +22,8 @@ trait MatchesSnapshots
use SnapshotDirectoryAware;
use SnapshotIdAware;

protected int $snapshotIncrementor = 0;

protected array $snapshotChanges = [];

/** @before */
#[Before]
public function setUpSnapshotIncrementor()
{
$this->snapshotIncrementor = 0;
}

/** @postCondition */
#[PostCondition]
public function markTestIncompleteIfSnapshotsHaveChanged()
Expand All @@ -55,78 +45,79 @@ public function markTestIncompleteIfSnapshotsHaveChanged()
$this->markTestIncomplete($formattedMessages);
}

public function assertMatchesSnapshot($actual, ?Driver $driver = null): void
public function assertMatchesSnapshot($actual, ?Driver $driver = null, ?string $id = null): void
{
if (! is_null($driver)) {
$this->doSnapshotAssertion($actual, $driver);
$this->doSnapshotAssertion($actual, $driver, $id);

return;
}

if (is_string($actual) || is_int($actual) || is_float($actual)) {
$this->doSnapshotAssertion($actual, new TextDriver);
$this->doSnapshotAssertion($actual, new TextDriver, $id);

return;
}

$this->doSnapshotAssertion($actual, new ObjectDriver);
$this->doSnapshotAssertion($actual, new ObjectDriver, $id);
}

public function assertMatchesFileHashSnapshot(string $filePath): void
public function assertMatchesFileHashSnapshot(string $filePath, ?string $id = null): void
{
if (! file_exists($filePath)) {
$this->fail('File does not exist');
}

$actual = sha1_file($filePath);

$this->assertMatchesSnapshot($actual);
$this->assertMatchesSnapshot($actual, null, $id);
}

public function assertMatchesFileSnapshot(string $file): void
public function assertMatchesFileSnapshot(string $file, ?string $id = null): void
{
$this->doFileSnapshotAssertion($file);
$this->doFileSnapshotAssertion($file, $id);
}

public function assertMatchesHtmlSnapshot(string $actual): void
public function assertMatchesHtmlSnapshot(string $actual, ?string $id = null): void
{
$this->assertMatchesSnapshot($actual, new HtmlDriver);
$this->assertMatchesSnapshot($actual, new HtmlDriver, $id);
}

public function assertMatchesJsonSnapshot($actual): void
public function assertMatchesJsonSnapshot($actual, ?string $id = null): void
{
$this->assertMatchesSnapshot($actual, new JsonDriver);
$this->assertMatchesSnapshot($actual, new JsonDriver, $id);
}

public function assertMatchesObjectSnapshot($actual): void
public function assertMatchesObjectSnapshot($actual, ?string $id = null): void
{
$this->assertMatchesSnapshot($actual, new ObjectDriver);
$this->assertMatchesSnapshot($actual, new ObjectDriver, $id);
}

public function assertMatchesTextSnapshot($actual): void
public function assertMatchesTextSnapshot($actual, ?string $id = null): void
{
$this->assertMatchesSnapshot($actual, new TextDriver);
$this->assertMatchesSnapshot($actual, new TextDriver, $id);
}

public function assertMatchesXmlSnapshot($actual): void
public function assertMatchesXmlSnapshot($actual, ?string $id = null): void
{
$this->assertMatchesSnapshot($actual, new XmlDriver);
$this->assertMatchesSnapshot($actual, new XmlDriver, $id);
}

public function assertMatchesYamlSnapshot($actual): void
public function assertMatchesYamlSnapshot($actual, ?string $id = null): void
{
$this->assertMatchesSnapshot($actual, new YamlDriver);
$this->assertMatchesSnapshot($actual, new YamlDriver, $id);
}

public function assertMatchesImageSnapshot(
$actual,
float $threshold = 0.1,
bool $includeAa = true
bool $includeAa = true,
?string $id = null
): void {
$this->assertMatchesSnapshot($actual, new ImageDriver(
$threshold,
$includeAa,
));
), $id);
}

/*
Expand Down Expand Up @@ -170,12 +161,10 @@ protected function shouldCreateSnapshots(): bool
&& getenv('CREATE_SNAPSHOTS') !== 'false';
}

protected function doSnapshotAssertion(mixed $actual, Driver $driver)
protected function doSnapshotAssertion(mixed $actual, Driver $driver, ?string $id = null)
{
$this->snapshotIncrementor++;

$snapshot = Snapshot::forTestCase(
$this->getSnapshotId(),
$this->getSnapshotId($id),
$this->getSnapshotDirectory(),
$driver
);
Expand Down Expand Up @@ -206,7 +195,7 @@ protected function doSnapshotAssertion(mixed $actual, Driver $driver)
}
}

protected function doFileSnapshotAssertion(string $filePath): void
protected function doFileSnapshotAssertion(string $filePath, ?string $id = null): void
{
if (! file_exists($filePath)) {
$this->fail('File does not exist');
Expand All @@ -220,9 +209,7 @@ protected function doFileSnapshotAssertion(string $filePath): void

$fileSystem = Filesystem::inDirectory($this->getFileSnapshotDirectory());

$this->snapshotIncrementor++;

$snapshotId = $this->getSnapshotId().'.'.$fileExtension;
$snapshotId = $this->getSnapshotId($id).'.'.$fileExtension;
$snapshotId = Filename::cleanFilename($snapshotId);

// If $filePath has a different file extension than the snapshot, the test should fail
Expand Down
93 changes: 93 additions & 0 deletions tests/Integration/AssertionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,97 @@ public function can_do_multiple_snapshot_assertions()
$this->assertMatchesSnapshot('Foo');
$this->assertMatchesSnapshot('Bar');
}

#[Test]
public function can_match_a_snapshot_with_explicit_id()
{
$this->assertMatchesSnapshot('Foo', null, 'my-snapshot');
}

#[Test]
public function can_match_a_json_snapshot_with_explicit_id()
{
$this->assertMatchesJsonSnapshot('{"foo":"bar"}', 'my-json-snapshot');
}

#[Test]
public function can_match_an_html_snapshot_with_explicit_id()
{
$this->assertMatchesHtmlSnapshot('<html><body>Hello</body></html>', 'my-html-snapshot');
}

#[Test]
public function can_match_an_xml_snapshot_with_explicit_id()
{
$this->assertMatchesXmlSnapshot('<root><item>Test</item></root>', 'my-xml-snapshot');
}

#[Test]
public function can_match_a_text_snapshot_with_explicit_id()
{
$this->assertMatchesTextSnapshot('Hello World', 'my-text-snapshot');
}

#[Test]
public function can_match_an_object_snapshot_with_explicit_id()
{
$this->assertMatchesObjectSnapshot(['key' => 'value'], 'my-object-snapshot');
}

#[Test]
public function can_match_a_yaml_snapshot_with_explicit_id()
{
$this->assertMatchesYamlSnapshot(['name' => 'test'], 'my-yaml-snapshot');
}

#[Test]
public function can_match_a_file_hash_snapshot_with_explicit_id()
{
$filePath = __DIR__.'/stubs/example_snapshots/snapshot.json';

$this->assertMatchesFileHashSnapshot($filePath, 'my-file-hash-snapshot');
}

#[Test]
public function can_match_a_file_snapshot_with_explicit_id()
{
$filePath = __DIR__.'/stubs/test_files/friendly_man.jpg';

$this->assertMatchesFileSnapshot($filePath, 'my-file-snapshot');
}

#[Test]
public function explicit_ids_do_not_affect_auto_increment_ids()
{
// First auto-increment: __1
$this->assertMatchesSnapshot('First');

// Explicit ID: __s-named
$this->assertMatchesSnapshot('Named', null, 'named');

// Second auto-increment should be __2, not __3
$this->assertMatchesSnapshot('Second');

// Another explicit ID
$this->assertMatchesSnapshot('AnotherNamed', null, 'another-named');

// Third auto-increment should be __3
$this->assertMatchesSnapshot('Third');
}

#[Test]
public function numeric_explicit_ids_do_not_conflict_with_auto_increment_ids()
{
// Explicit ID with numeric value that could conflict: __s-1
$this->assertMatchesSnapshot('ExplicitOne', null, '1');

// Auto-increment: __1 (should not conflict with __s-1)
$this->assertMatchesSnapshot('AutoOne');

// Another explicit numeric ID: __s-2
$this->assertMatchesSnapshot('ExplicitTwo', null, '2');

// Auto-increment: __2 (should not conflict with __s-2)
$this->assertMatchesSnapshot('AutoTwo');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
f558f8149e33fba2916877b2d3de4a42ebd544b4
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"foo":"bar"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Foo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello World
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
name: test
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<html><body>Hello</body></html>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
key: value
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0"?>
<root>
<item>Test</item>
</root>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
First
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Second
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Third
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
AnotherNamed
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Named
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
AutoOne
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
AutoTwo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ExplicitOne
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ExplicitTwo
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.