From 59920c0313bc6c0c5699b6f84b03eead712760ed Mon Sep 17 00:00:00 2001 From: Greg Furman Date: Mon, 23 Jun 2025 14:15:19 +0200 Subject: [PATCH] fix(snapshot): Support args with skip_snapshot_verify marker --- localstack_snapshot/pytest/snapshot.py | 11 +++- tests/test_snapshots_integration.py | 74 ++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 tests/test_snapshots_integration.py diff --git a/localstack_snapshot/pytest/snapshot.py b/localstack_snapshot/pytest/snapshot.py index c6885d1..68bb6c0 100644 --- a/localstack_snapshot/pytest/snapshot.py +++ b/localstack_snapshot/pytest/snapshot.py @@ -71,8 +71,17 @@ def pytest_runtest_call(item: Item) -> None: if not is_aws(): # only skip for local tests for m in item.iter_markers(name="skip_snapshot_verify"): skip_paths = m.kwargs.get("paths", []) - skip_condition = m.kwargs.get("condition") + + if not (skip_paths or skip_condition) and m.args: + (skip_paths, *_skip_condition) = m.args + if _skip_condition: + skip_condition, *_ = _skip_condition + + if skip_paths: + if not isinstance(skip_paths, list): + raise ValueError("paths must be a list") + # can optionally include a condition, when this will be skipped # a condition must be a Callable returning something truthy/falsey if skip_condition: diff --git a/tests/test_snapshots_integration.py b/tests/test_snapshots_integration.py new file mode 100644 index 0000000..794ed5c --- /dev/null +++ b/tests/test_snapshots_integration.py @@ -0,0 +1,74 @@ +import os +import tempfile + +import pytest + +from localstack_snapshot.snapshots import SnapshotSession + +pytest_plugins = [ + "localstack_snapshot.pytest.snapshot", +] + + +@pytest.fixture +def snapshot(): + with tempfile.TemporaryDirectory() as temp_dir: + session = SnapshotSession( + scope_key="test", + verify=True, + base_file_path=os.path.join(temp_dir, "test"), + update=False, + ) + yield session + + +class TestSnapshotIntegration: + @pytest.mark.skip_snapshot_verify(paths=["$..id"]) + def test_skip_id_field_passes(self, snapshot): + snapshot.recorded_state = {"user": {"name": "John", "id": "old"}} + snapshot.match("user", {"name": "John", "id": "new"}) + + # HACK(gregfurman): xfail(strict=True) means we expect the test to fail -- where the underlying test failing + # results in an expected XFAIL, skipping the test. Otherwise, a PASS should trigger a true FAIL. + @pytest.mark.xfail(strict=True, reason="Should fail because name differs, only ID is skipped") + @pytest.mark.skip_snapshot_verify(paths=["$..id"]) + def test_skip_id_but_name_differs_fails(self, snapshot): + snapshot.recorded_state = {"user": {"name": "John", "id": "old"}} + snapshot.match("user", {"name": "Jane", "id": "new"}) + + @pytest.mark.xfail(strict=True, reason="Should fail because name differs, only ID is skipped") + @pytest.mark.skip_snapshot_verify(["$..id"]) + def test_skip_id_field_passes_args(self, snapshot): + snapshot.recorded_state = {"user": {"name": "John", "id": "old"}} + snapshot.match("user", {"name": "Jane", "id": "new"}) + + @pytest.mark.xfail(strict=True, reason="Should fail because no fields are skipped") + def test_no_skip_marker_fails(self, snapshot): + snapshot.recorded_state = {"user": {"name": "John", "id": "old"}} + snapshot.match("user", {"name": "John", "id": "new"}) + + @pytest.mark.skip_snapshot_verify(paths=["$..id", "$..timestamp"]) + def test_skip_multiple_fields_passes(self, snapshot): + snapshot.recorded_state = {"event": {"type": "login", "id": "123", "timestamp": "old"}} + snapshot.match("event", {"type": "login", "id": "456", "timestamp": "new"}) + + @pytest.mark.skip_snapshot_verify(condition=lambda: True) + def test_condition_true_skips_all_verification(self, snapshot): + snapshot.recorded_state = {"data": "old"} + snapshot.match("data", "completely_different") + + @pytest.mark.skip_snapshot_verify(condition=lambda: False, paths=["$..id"]) + def test_condition_false_ignores_paths(self, snapshot): + snapshot.recorded_state = {"user": {"name": "John", "id": "123"}} + snapshot.match("user", {"name": "John", "id": "123"}) + + @pytest.mark.skip_snapshot_verify(["$..id"], lambda: True) + def test_condition_with_args_skips_all(self, snapshot): + snapshot.recorded_state = {"data": {"id": "old"}} + snapshot.match("data", {"id": "new"}) + + @pytest.mark.xfail(strict=True, reason="Should fail because condition is False") + @pytest.mark.skip_snapshot_verify(["$..id"], lambda: False) + def test_condition_false_with_args_fails(self, snapshot): + snapshot.recorded_state = {"user": {"name": "John", "id": "old"}} + snapshot.match("user", {"name": "John", "id": "new"})