From c264f6cb94f62bfab7f777b8e3a511132ce2f0f5 Mon Sep 17 00:00:00 2001 From: Adam Smith <2105363+adamjs83@users.noreply.github.com> Date: Thu, 17 Sep 2026 21:54:27 -0400 Subject: [PATCH] test: pin the snapshot fixture to Home Assistant's extension The ported suite passes in CI and fails locally on the same commit, same Python (3.14.7) and byte-identical dependency versions (syrupy 6.0.0, pytest 9.0.3, pytest-homeassistant-custom-component 0.13.365, HA 2026.9.2): tests/test_conversation.py::test_model_args fails with "Snapshot 'test_model_args[subentry_options0]' does not exist!" even though tests/snapshots/test_conversation.ambr contains exactly that key. Cause: syrupy and pytest-homeassistant-custom-component both register a `snapshot` fixture via the pytest11 entry point, and the plugin loaded last wins. syrupy's stores snapshots in `__snapshots__/`; HomeAssistantSnapshotExtension overrides dirname() to `snapshots/`, which is where core's ported .ambr files are. Entry-point iteration order is install/filesystem dependent, so which one wins varies per machine -- confirmed by running with --snapshot-update locally, which wrote a new file to tests/__snapshots__/ instead of finding the committed one under tests/snapshots/. That means the green CI run was luck, not design: any change to install order could have flipped it, and the failure mode is a *missing* snapshot, which reads like a stale fixture rather than a harness bug. Fixed the way core's own tests/conftest.py does it -- redefine `snapshot` in conftest, since a conftest fixture always takes precedence over a plugin's. This is the one piece of core's conftest the port dropped. Local: 137 passed (was 136 passed, 1 failed). Matches CI's 137. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01NxJYWgGJtCw13qUHZtG8ki --- tests/conftest.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/conftest.py b/tests/conftest.py index 05b6b65..7c26e17 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -41,6 +41,8 @@ from homeassistant.helpers import llm from homeassistant.setup import async_setup_component from pytest_homeassistant_custom_component.common import MockConfigEntry +from pytest_homeassistant_custom_component.syrupy import HomeAssistantSnapshotExtension +from syrupy.assertion import SnapshotAssertion pytest_plugins = "pytest_homeassistant_custom_component" @@ -51,6 +53,25 @@ def auto_enable_custom_integrations(enable_custom_integrations): return +@pytest.fixture +def snapshot(snapshot: SnapshotAssertion) -> SnapshotAssertion: + """Return the snapshot fixture with Home Assistant's extension. + + Both pytest-homeassistant-custom-component and syrupy register a + `snapshot` fixture through the pytest11 entry point, and the plugin that + happens to load last wins. syrupy's own fixture stores snapshots in + `__snapshots__/`, while HomeAssistantSnapshotExtension uses `snapshots/` + -- which is where core's ported .ambr files live. Whichever fixture wins + is therefore decided by entry-point iteration order, which varies between + machines: CI resolved the HA one and passed, while a local run resolved + syrupy's and failed with "snapshot does not exist". + + Redefining it here (as core's own tests/conftest.py does) pins it: a + conftest fixture always takes precedence over a plugin's. + """ + return snapshot.use_extension(HomeAssistantSnapshotExtension) + + @pytest.fixture def mock_conversation_subentry_data() -> dict[str, Any]: """Mock subentry data."""