Skip to content

Commit

Permalink
fix: check current session's pending-write queue when recalling snaps…
Browse files Browse the repository at this point in the history
…hots (e.g. diffing)
  • Loading branch information
huonw committed Dec 23, 2024
1 parent ef8189c commit 204026a
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 9 deletions.
6 changes: 1 addition & 5 deletions src/syrupy/assertion.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,11 +377,7 @@ def _recall_data(
) -> Tuple[Optional["SerializableData"], bool]:
try:
return (
self.extension.read_snapshot(
test_location=self.test_location,
index=index,
session_id=str(id(self.session)),
),
self.session.recall_snapshot(self.extension, self.test_location, index),
False,
)
except SnapshotDoesNotExist:
Expand Down
37 changes: 33 additions & 4 deletions src/syrupy/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,25 @@ class SnapshotSession:
List[Tuple["SerializedData", "PyTestLocation", "SnapshotIndex"]],
] = field(default_factory=dict)

def queue_snapshot_write(
def _snapshot_write_queue_key(
self,
extension: "AbstractSyrupyExtension",
test_location: "PyTestLocation",
data: "SerializedData",
index: "SnapshotIndex",
) -> None:
) -> Tuple[Type["AbstractSyrupyExtension"], str]:
snapshot_location = extension.get_location(
test_location=test_location, index=index
)
key = (extension.__class__, snapshot_location)
return (extension.__class__, snapshot_location)

def queue_snapshot_write(
self,
extension: "AbstractSyrupyExtension",
test_location: "PyTestLocation",
data: "SerializedData",
index: "SnapshotIndex",
) -> None:
key = self._snapshot_write_queue_key(extension, test_location, index)
queue = self._queued_snapshot_writes.get(key, [])
queue.append((data, test_location, index))
self._queued_snapshot_writes[key] = queue
Expand All @@ -93,6 +101,27 @@ def flush_snapshot_write_queue(self) -> None:
)
self._queued_snapshot_writes = {}

def recall_snapshot(
self,
extension: "AbstractSyrupyExtension",
test_location: "PyTestLocation",
index: "SnapshotIndex",
) -> Optional["SerializedData"]:
"""Find the current value of the snapshot, for this session, either a pending write or the actual snapshot."""

key = self._snapshot_write_queue_key(extension, test_location, index)
queue = self._queued_snapshot_writes.get(key)
if queue:
# find the last (i.e. most recent) write to this index in the queue:
for queue_data, queue_test_location, queue_index in reversed(queue):
if queue_index == index and queue_test_location == test_location:
return queue_data

# no queue, or no matching write, so just read the snapshot directly:
return extension.read_snapshot(
test_location=test_location, index=index, session_id=str(id(self))
)

@property
def update_snapshots(self) -> bool:
return bool(self.pytest_session.config.option.update_snapshots)
Expand Down
56 changes: 56 additions & 0 deletions tests/integration/test_snapshot_diff.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import pytest

_TEST = """
def test_foo(snapshot):
assert {**base} == snapshot(name="a")
assert {**base, **extra} == snapshot(name="b", diff="a")
"""


def _make_file(testdir, base, extra):
testdir.makepyfile(
test_file="\n\n".join([f"base = {base!r}", f"extra = {extra!r}", _TEST])
)


def _run_test(testdir, base, extra, expected_update_lines):
_make_file(testdir, base=base, extra=extra)

# Run with --snapshot-update, to generate/update snapshots:
result = testdir.runpytest(
"-v",
"--snapshot-update",
)
result.stdout.re_match_lines((expected_update_lines,))
assert result.ret == 0

# Run without --snapshot-update, to validate the snapshots are actually up-to-date
result = testdir.runpytest("-v")
result.stdout.re_match_lines((r"2 snapshots passed\.",))
assert result.ret == 0


def test_diff_lifecycle(testdir) -> pytest.Testdir:
# first: create both snapshots completely from scratch
_run_test(
testdir,
base={"A": 1},
extra={"X": 10},
expected_update_lines=r"2 snapshots generated\.",
)

# second: edit the base data, to change the data for both snapshots (only changes the serialized output for the base snapshot `a`).
_run_test(
testdir,
base={"A": 1, "B": 2},
extra={"X": 10},
expected_update_lines=r"1 snapshot passed. 1 snapshot updated\.",
)

# third: edit just the extra data (only changes the serialized output for the diff snapshot `b`)
_run_test(
testdir,
base={"A": 1, "B": 2},
extra={"X": 10, "Y": 20},
expected_update_lines=r"1 snapshot passed. 1 snapshot updated\.",
)

0 comments on commit 204026a

Please sign in to comment.