test: cross-file stub-scoping repairs — hub ConfigFlow base carries the full plumbing, standalone rebuilds when its holder is gone, test_init scoped hygiene mirrors scoped_stubs (completes t30 G6)

This commit is contained in:
James Mackay committed 2026-10-09 07:38:24 +01:00
1 parent 80ddff313a
commit e77bc12d81
2 files changed
+40 -3

No files matched your search

+31 -1
View File
@@ -131,8 +131,38 @@ def install() -> None:
config_entries = types.ModuleType("homeassistant.config_entries") config_entries = types.ModuleType("homeassistant.config_entries")
config_entries.ConfigEntry = type("ConfigEntry", (), {}) config_entries.ConfigEntry = type("ConfigEntry", (), {})
async def _stub_set_unique_id(self, unique_id):
# hub shape: record; a full flow test file scopes its own version
self._unique_id = unique_id
def _noop_abort(self, *, error=None, **kwargs):
return None
class _ConfigFlowStub: class _ConfigFlowStub:
"""ConfigFlow shape used by flow tests (t29 G3a API included).""" """ConfigFlow shape used by entity tests (t29 G3a API included).
Late loads under the hub stubs (e.g. test_init designs run AFTER the
other flow files) still get the base plumbing the flow modules rely
on — show/create/abort/unique-id — so the flow classes never import
against a bare base.
"""
async_set_unique_id = _stub_set_unique_id
_abort_if_unique_id_configured = _noop_abort
def async_show_form(self, *, step_id, data_schema=None, errors=None):
return {
"type": "form",
"step_id": step_id,
"errors": dict(errors or {}),
"data_schema": data_schema,
}
def async_create_entry(self, *, title, data, options=None):
return {"type": "create_entry", "title": title, "data": data}
def async_abort(self, *, reason):
return {"type": "abort", "reason": reason}
def _get_reauth_entry(self, entry=None): def _get_reauth_entry(self, entry=None):
if entry is not None: if entry is not None:
+9 -2
View File
@@ -37,8 +37,15 @@ _STUB_NAMES = (
def _install_stubs() -> None: def _install_stubs() -> None:
"""Import-time stand-ins (idempotent; same shape as the pairing tests).""" """Import-time stand-ins (idempotent; same shape as the pairing tests).
if sys.modules.get("voluptuous") is not None:
t30: the guard rebuilds whenever the module-level holder is missing —
a later file's scoped teardown may pop the shared stubs this file's
tests rely on (the flow-class surfaces live on the local base which we
MUST rebind against)."""
if sys.modules.get("voluptuous") is not None and hasattr(
sys.modules.get(__name__), "_zc_holder"
):
return return
vol = types.ModuleType("voluptuous") vol = types.ModuleType("voluptuous")