From 2dbb30984467a40bccf5bfce82477ad64b55d2b1 Mon Sep 17 00:00:00 2001 From: Joshua King Date: Sun, 13 Sep 2026 18:34:19 -0400 Subject: [PATCH] test: wire pytest test harness with standard hass fixture --- pyproject.toml | 2 ++ tests/conftest.py | 58 +++++++++++++++++++++++++++++++++++++++++++++++ uv.lock | 24 ++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 tests/conftest.py diff --git a/pyproject.toml b/pyproject.toml index d7bdfe5..6d77648 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,9 +9,11 @@ dependencies = [] [dependency-groups] dev = [ "pytest>=8.0.0", + "pytest-asyncio>=0.24", "voluptuous>=0.14", ] [tool.pytest.ini_options] testpaths = ["tests"] pythonpath = ["."] +asyncio_mode = "auto" diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..4b8dd32 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,58 @@ +"""Shared pytest fixtures for the NestQuest test suite. + +pytest-homeassistant-custom-component could not be adopted: it pins +``pytest==9.0.3`` and ``voluptuous==0.13.1``, which conflicts with the dev +group's ``voluptuous>=0.14`` (used directly by the options flow's schema and +its tests), and its back-releases raise the floor to Python >=3.12 while this +project supports >=3.11. The documented fallback is therefore used: +``pytest-asyncio`` plus a standard-shaped ``hass`` fixture below. + +The tests mock the ``homeassistant`` package via ``sys.modules`` injection; +this conftest wires the mock modules before any test module import and +provides the standard ``hass`` fixture shape (``config``, ``config_entries``, +``data``, ``loop``) that HA's own harness exposes. +""" + +from __future__ import annotations + +import asyncio +import sys +from types import SimpleNamespace +from unittest.mock import MagicMock + +import pytest + +# Mock homeassistant modules if not installed in the environment. Runs in +# conftest so it precedes every test module's import of the integration. +for _mod in ( + "homeassistant", + "homeassistant.core", + "homeassistant.config_entries", + "homeassistant.data_entry_flow", +): + sys.modules.setdefault(_mod, MagicMock()) + +# Wire parent package attributes so "from homeassistant import config_entries" +# resolves to the mocked submodule, mirroring real HA's package layout. +sys.modules["homeassistant"].config_entries = sys.modules["homeassistant.config_entries"] +sys.modules["homeassistant"].data_entry_flow = sys.modules["homeassistant.data_entry_flow"] + + +@pytest.fixture +def hass(): + """Provide a standard-shaped hass fixture. + + Mirrors the surface of Home Assistant's ``hass`` fixture: a ``config`` + namespace, a ``config_entries`` manager, a ``data`` dict for integration + state, and the running event ``loop``. + """ + hass = SimpleNamespace( + data={}, + config=MagicMock(), + config_entries=MagicMock(), + ) + hass.loop = asyncio.new_event_loop() + try: + yield hass + finally: + hass.loop.close() \ No newline at end of file diff --git a/uv.lock b/uv.lock index 2dbaa28..185f269 100644 --- a/uv.lock +++ b/uv.lock @@ -28,6 +28,7 @@ source = { virtual = "." } [package.dev-dependencies] dev = [ { name = "pytest" }, + { name = "pytest-asyncio" }, { name = "voluptuous" }, ] @@ -36,6 +37,7 @@ dev = [ [package.metadata.requires-dev] dev = [ { name = "pytest", specifier = ">=8.0.0" }, + { name = "pytest-asyncio", specifier = ">=0.24" }, { name = "voluptuous", specifier = ">=0.14" }, ] @@ -82,6 +84,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, ] +[[package]] +name = "pytest-asyncio" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/43/7c/d36d04db312ecf4298932ef77e6e4a9e8ad017906e24e34f0b0c361a2473/pytest_asyncio-1.4.0.tar.gz", hash = "sha256:c6c0d2259945122819f171a32ecea2c349ead889ee28176caaf492143424be42", size = 58514, upload-time = "2026-05-26T09:56:04.083Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/e2/08a497ef684b88559c9cc5f4ad53a37e7b99e727094a86d6ea32536d5d3c/pytest_asyncio-1.4.0-py3-none-any.whl", hash = "sha256:933ca923a23075a87fb7070c0ec272a6848489824d887c85c812670932835aa1", size = 16930, upload-time = "2026-05-26T09:56:02.576Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, +] + [[package]] name = "voluptuous" version = "0.16.0"