Skip to content

Commit

Permalink
feat: add option to disable diffing (#924)
Browse files Browse the repository at this point in the history
For extremely large snapshot files, the diff algorithm is not very efficient. Until the algorithm can be modified to work with large files, there is now a --snapshot-diff-mode=disabled flag that can be specified to disable diffing on snapshot assertion failures.
  • Loading branch information
noahnu authored Nov 23, 2024
1 parent 8c1208d commit d283e87
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 8 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ These are the cli options exposed to `pytest` by the plugin.
| `--snapshot-default-extension` | Use to change the default snapshot extension class. | [AmberSnapshotExtension](https://github.com/syrupy-project/syrupy/blob/main/src/syrupy/extensions/amber/__init__.py) |
| `--snapshot-no-colors` | Disable test results output highlighting. Equivalent to setting the environment variables `ANSI_COLORS_DISABLED` or `NO_COLOR` | Disabled by default if not in terminal. |
| `--snapshot-patch-pycharm-diff`| Override PyCharm's default diffs viewer when looking at snapshot diffs. See [IDE Integrations](#ide-integrations) | `False` |
| `--snapshot-diff-mode` | Configures how diffs are displayed on assertion failure. If working with very large snapshots, disabling the diff can improve performance. | `detailed` |

### Assertion Options

Expand Down
24 changes: 18 additions & 6 deletions src/syrupy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

import pytest

from .assertion import SnapshotAssertion
from .assertion import DiffMode, SnapshotAssertion
from .constants import DISABLE_COLOR_ENV_VAR
from .exceptions import FailedToLoadModuleMember
from .extensions import DEFAULT_EXTENSION
Expand Down Expand Up @@ -43,7 +43,7 @@ def __import_extension(value: Optional[str]) -> Any:
raise argparse.ArgumentTypeError(e) from e


def pytest_addoption(parser: Any) -> None:
def pytest_addoption(parser: "pytest.Parser") -> None:
"""
Exposes snapshot plugin configuration to pytest.
https://docs.pytest.org/en/latest/reference.html#_pytest.hookspec.pytest_addoption
Expand Down Expand Up @@ -94,9 +94,17 @@ def pytest_addoption(parser: Any) -> None:
dest="patch_pycharm_diff",
help="Patch PyCharm diff",
)
group.addoption(
"--snapshot-diff-mode",
default=DiffMode.DETAILED,
choices=list(DiffMode),
type=DiffMode,
dest="diff_mode",
help="Controls how diffs are represented on snapshot assertion failure",
)


def __terminal_color(config: Any) -> "ContextManager[None]":
def __terminal_color(config: "pytest.Config") -> "ContextManager[None]":
env = {}
if config.option.no_colors:
env[DISABLE_COLOR_ENV_VAR] = "true"
Expand All @@ -105,7 +113,7 @@ def __terminal_color(config: Any) -> "ContextManager[None]":


def pytest_assertrepr_compare(
config: Any, op: str, left: Any, right: Any
config: "pytest.Config", op: str, left: Any, right: Any
) -> Optional[List[str]]:
"""
Return explanation for comparisons in failing assert expressions.
Expand All @@ -119,10 +127,14 @@ def snapshot_name(name: str) -> str:

if isinstance(left, SnapshotAssertion):
assert_msg = reset(f"{snapshot_name(left.name)} {op} {received_name}")
return [assert_msg] + left.get_assert_diff()
return [assert_msg] + left.get_assert_diff(
diff_mode=config.option.diff_mode
)
elif isinstance(right, SnapshotAssertion):
assert_msg = reset(f"{received_name} {op} {snapshot_name(right.name)}")
return [assert_msg] + right.get_assert_diff()
return [assert_msg] + right.get_assert_diff(
diff_mode=config.option.diff_mode
)
return None


Expand Down
16 changes: 14 additions & 2 deletions src/syrupy/assertion.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
dataclass,
field,
)
from enum import Enum
from gettext import gettext
from typing import (
TYPE_CHECKING,
Expand Down Expand Up @@ -35,6 +36,14 @@
)


class DiffMode(Enum):
DETAILED = "detailed"
DISABLED = "disabled"

def __str__(self) -> str:
return self.value


@dataclass
class AssertionResult:
snapshot_location: str
Expand Down Expand Up @@ -210,7 +219,9 @@ def _serialize(self, data: "SerializableData") -> "SerializedData":
data, exclude=self._exclude, include=self._include, matcher=self.__matcher
)

def get_assert_diff(self) -> List[str]:
def get_assert_diff(
self, *, diff_mode: "DiffMode" = DiffMode.DETAILED
) -> List[str]:
assertion_result = self._execution_results[self.num_executions - 1]
if assertion_result.exception:
if isinstance(assertion_result.exception, (TaintedSnapshotError,)):
Expand Down Expand Up @@ -247,7 +258,8 @@ def get_assert_diff(self) -> List[str]:
)
if not assertion_result.success:
snapshot_data = snapshot_data if snapshot_data is not None else ""
diff.extend(self.extension.diff_lines(serialized_data, snapshot_data))
if diff_mode == DiffMode.DETAILED:
diff.extend(self.extension.diff_lines(serialized_data, snapshot_data))
return diff

def __with_prop(self, prop_name: str, prop_value: Any) -> None:
Expand Down
49 changes: 49 additions & 0 deletions tests/integration/test_snapshot_option_diff_mode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import pytest


@pytest.fixture
def testfile(testdir) -> pytest.Testdir:
testdir.makepyfile(
test_file=(
"""
def test_case(snapshot):
assert snapshot == "some-value"
"""
),
)
return testdir


def test_diff_mode_disabled_does_not_print_diff(
testfile,
):
# Generate initial snapshot
result = testfile.runpytest("-v", "--snapshot-update")
result.stdout.re_match_lines((r"1 snapshot generated\.",))
assert result.ret == 0

# Modify snapshot to generate diff
testfile.makepyfile(
test_file=(
"""
def test_case(snapshot):
assert snapshot == "some-other-value"
"""
),
)

# With diff we expect to see "some-other-value"
result = testfile.runpytest("-v", "--snapshot-diff-mode=detailed")
result.stdout.re_match_lines(
(
r".*- 'some-value'",
r".*\+ 'some-other-value'",
)
)
assert result.ret == 1

# Without diff we do not expect to see "some-other-value"
result = testfile.runpytest("-v", "--snapshot-diff-mode=disabled")
result.stdout.no_re_match_line(r".*- 'some-value'")
result.stdout.no_re_match_line(r".*\+ 'some-other-value'")
assert result.ret == 1
7 changes: 7 additions & 0 deletions tests/syrupy/__snapshots__/test_diff_mode.ambr
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# serializer version: 1
# name: test_can_be_stringified
'detailed'
# ---
# name: test_can_be_stringified.1
'disabled'
# ---
6 changes: 6 additions & 0 deletions tests/syrupy/test_diff_mode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from syrupy.assertion import DiffMode


def test_can_be_stringified(snapshot):
assert snapshot == str(DiffMode.DETAILED)
assert snapshot == str(DiffMode.DISABLED)

0 comments on commit d283e87

Please sign in to comment.