Refactor Tile tests (#134130)

This commit is contained in:
Joost Lekkerkerker 2024-12-28 12:37:21 +01:00 committed by GitHub
parent 14059c6df8
commit 590f0ce61f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 187 additions and 78 deletions

View File

@ -1 +1,13 @@
"""Define tests for the Tile component.""" """Tests for the Tile integration."""
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
async def setup_integration(hass: HomeAssistant, config_entry: MockConfigEntry) -> None:
"""Fixture for setting up the component."""
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()

View File

@ -1,77 +1,77 @@
"""Define test fixtures for Tile.""" """Define test fixtures for Tile."""
from collections.abc import Generator from collections.abc import Generator
import json from datetime import datetime
from typing import Any from unittest.mock import AsyncMock, patch
from unittest.mock import AsyncMock, Mock, patch
import pytest import pytest
from pytile.api import API
from pytile.tile import Tile from pytile.tile import Tile
from homeassistant.components.tile.const import DOMAIN from homeassistant.components.tile.const import DOMAIN
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry, load_fixture from .const import TEST_PASSWORD, TEST_USERNAME
TEST_PASSWORD = "123abc" from tests.common import MockConfigEntry
TEST_USERNAME = "user@host.com"
@pytest.fixture(name="api") @pytest.fixture
def api_fixture(data_tile_details: dict[str, Any]) -> Mock: def tile() -> AsyncMock:
"""Define a pytile API object.""" """Define a Tile object."""
tile = Tile(None, data_tile_details) mock = AsyncMock(spec=Tile)
tile.async_update = AsyncMock() mock.uuid = "19264d2dffdbca32"
mock.name = "Wallet"
mock.as_dict.return_value = {
"accuracy": 13.496111,
"altitude": 0,
"archetype": "WALLET",
"dead": False,
"firmware_version": "01.12.14.0",
"hardware_version": "02.09",
"kind": "TILE",
"last_timestamp": datetime(2020, 8, 12, 17, 55, 26),
"latitude": 0,
"longitude": 0,
"lost": False,
"lost_timestamp": datetime(1969, 12, 31, 19, 0, 0),
"name": "Wallet",
"ring_state": "STOPPED",
"uuid": "19264d2dffdbca32",
"visible": True,
"voip_state": "OFFLINE",
}
return mock
return Mock(
async_get_tiles=AsyncMock( @pytest.fixture
return_value={data_tile_details["result"]["tile_uuid"]: tile} def mock_config_entry() -> MockConfigEntry:
) """Define a config entry fixture."""
return MockConfigEntry(
domain=DOMAIN,
unique_id=TEST_USERNAME,
data={CONF_USERNAME: TEST_USERNAME, CONF_PASSWORD: TEST_PASSWORD},
) )
@pytest.fixture(name="config_entry") @pytest.fixture
def config_entry_fixture( def mock_pytile(tile: AsyncMock) -> Generator[None]:
hass: HomeAssistant, config: dict[str, Any]
) -> MockConfigEntry:
"""Define a config entry fixture."""
entry = MockConfigEntry(domain=DOMAIN, unique_id=config[CONF_USERNAME], data=config)
entry.add_to_hass(hass)
return entry
@pytest.fixture(name="config")
def config_fixture() -> dict[str, Any]:
"""Define a config entry data fixture."""
return {
CONF_USERNAME: TEST_USERNAME,
CONF_PASSWORD: TEST_PASSWORD,
}
@pytest.fixture(name="data_tile_details", scope="package")
def data_tile_details_fixture():
"""Define a Tile details data payload."""
return json.loads(load_fixture("tile_details_data.json", "tile"))
@pytest.fixture(name="mock_pytile")
def mock_pytile_fixture(api: Mock) -> Generator[None]:
"""Define a fixture to patch pytile.""" """Define a fixture to patch pytile."""
client = AsyncMock(spec=API)
client.async_get_tiles = AsyncMock(return_value={"19264d2dffdbca32": tile})
with ( with (
patch( patch(
"homeassistant.components.tile.config_flow.async_login", return_value=api "homeassistant.components.tile.config_flow.async_login", return_value=client
), ),
patch("homeassistant.components.tile.async_login", return_value=api), patch("homeassistant.components.tile.async_login", return_value=client),
): ):
yield yield
@pytest.fixture(name="setup_config_entry") @pytest.fixture
async def setup_config_entry_fixture( def mock_setup_entry():
hass: HomeAssistant, config_entry: MockConfigEntry, mock_pytile: None """Mock async_setup_entry."""
) -> None: with patch(
"""Define a fixture to set up tile.""" "homeassistant.components.tile.async_setup_entry", return_value=True
assert await hass.config_entries.async_setup(config_entry.entry_id) ) as mock_setup_entry:
await hass.async_block_till_done() yield mock_setup_entry

View File

@ -0,0 +1,4 @@
"""Constants for the Tile component tests."""
TEST_PASSWORD = "123abc"
TEST_USERNAME = "user@host.com"

View File

@ -14,7 +14,7 @@
'latitude': '**REDACTED**', 'latitude': '**REDACTED**',
'longitude': '**REDACTED**', 'longitude': '**REDACTED**',
'lost': False, 'lost': False,
'lost_timestamp': '1969-12-31T23:59:59.999000', 'lost_timestamp': '1969-12-31T19:00:00',
'name': 'Wallet', 'name': 'Wallet',
'ring_state': 'STOPPED', 'ring_state': 'STOPPED',
'uuid': '**REDACTED**', 'uuid': '**REDACTED**',

View File

@ -16,15 +16,45 @@ from .conftest import TEST_PASSWORD, TEST_USERNAME
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
async def test_full_flow(
hass: HomeAssistant, mock_pytile: AsyncMock, mock_setup_entry: AsyncMock
) -> None:
"""Test a full flow."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_USERNAME: TEST_USERNAME,
CONF_PASSWORD: TEST_PASSWORD,
},
)
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == TEST_USERNAME
assert result["data"] == {
CONF_USERNAME: TEST_USERNAME,
CONF_PASSWORD: TEST_PASSWORD,
}
assert result["result"].unique_id == TEST_USERNAME
@pytest.mark.parametrize( @pytest.mark.parametrize(
("mock_login_response", "errors"), ("exception", "errors"),
[ [
(AsyncMock(side_effect=InvalidAuthError), {"base": "invalid_auth"}), (InvalidAuthError, {"base": "invalid_auth"}),
(AsyncMock(side_effect=TileError), {"base": "unknown"}), (TileError, {"base": "unknown"}),
], ],
) )
async def test_create_entry( async def test_create_entry(
hass: HomeAssistant, api, config, errors, mock_login_response, mock_pytile hass: HomeAssistant,
mock_pytile: AsyncMock,
mock_setup_entry: AsyncMock,
exception: Exception,
errors: dict[str, str],
) -> None: ) -> None:
"""Test creating an entry.""" """Test creating an entry."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
@ -33,46 +63,61 @@ async def test_create_entry(
assert result["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user" assert result["step_id"] == "user"
# Test errors that can arise:
with patch( with patch(
"homeassistant.components.tile.config_flow.async_login", mock_login_response "homeassistant.components.tile.config_flow.async_login", side_effect=exception
): ):
result = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=config result["flow_id"],
user_input={
CONF_USERNAME: TEST_USERNAME,
CONF_PASSWORD: TEST_PASSWORD,
},
) )
assert result["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user" assert result["step_id"] == "user"
assert result["errors"] == errors assert result["errors"] == errors
# Test that we can recover from login errors:
result = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=config result["flow_id"],
user_input={
CONF_USERNAME: TEST_USERNAME,
CONF_PASSWORD: TEST_PASSWORD,
},
) )
assert result["type"] is FlowResultType.CREATE_ENTRY assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == TEST_USERNAME
assert result["data"] == {
CONF_USERNAME: TEST_USERNAME,
CONF_PASSWORD: TEST_PASSWORD,
}
async def test_duplicate_error(hass: HomeAssistant, config, setup_config_entry) -> None: async def test_duplicate_error(
hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None:
"""Test that errors are shown when duplicates are added.""" """Test that errors are shown when duplicates are added."""
mock_config_entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=config DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_USERNAME: TEST_USERNAME,
CONF_PASSWORD: TEST_PASSWORD,
},
) )
assert result["type"] is FlowResultType.ABORT assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "already_configured" assert result["reason"] == "already_configured"
async def test_step_reauth( async def test_step_reauth(
hass: HomeAssistant, config, config_entry: MockConfigEntry, setup_config_entry hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_setup_entry: AsyncMock,
mock_pytile: AsyncMock,
) -> None: ) -> None:
"""Test that the reauth step works.""" """Test that the reauth step works."""
result = await config_entry.start_reauth_flow(hass) mock_config_entry.add_to_hass(hass)
assert result["step_id"] == "reauth_confirm" result = await mock_config_entry.start_reauth_flow(hass)
result = await hass.config_entries.flow.async_configure(result["flow_id"])
assert result["type"] is FlowResultType.FORM assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "reauth_confirm" assert result["step_id"] == "reauth_confirm"
@ -82,3 +127,45 @@ async def test_step_reauth(
assert result["type"] is FlowResultType.ABORT assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "reauth_successful" assert result["reason"] == "reauth_successful"
assert len(hass.config_entries.async_entries()) == 1 assert len(hass.config_entries.async_entries()) == 1
@pytest.mark.parametrize(
("exception", "errors"),
[
(InvalidAuthError, {"base": "invalid_auth"}),
(TileError, {"base": "unknown"}),
],
)
async def test_step_reauth_errors(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_setup_entry: AsyncMock,
mock_pytile: AsyncMock,
exception: Exception,
errors: dict[str, str],
) -> None:
"""Test that the reauth step can recover from an error."""
mock_config_entry.add_to_hass(hass)
result = await mock_config_entry.start_reauth_flow(hass)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "reauth_confirm"
with patch(
"homeassistant.components.tile.config_flow.async_login", side_effect=exception
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_PASSWORD: TEST_PASSWORD,
},
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "reauth_confirm"
assert result["errors"] == errors
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={CONF_PASSWORD: "password"}
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "reauth_successful"
assert len(hass.config_entries.async_entries()) == 1

View File

@ -1,22 +1,28 @@
"""Test Tile diagnostics.""" """Test Tile diagnostics."""
from unittest.mock import AsyncMock
from syrupy import SnapshotAssertion from syrupy import SnapshotAssertion
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from . import setup_integration
from tests.common import MockConfigEntry
from tests.components.diagnostics import get_diagnostics_for_config_entry from tests.components.diagnostics import get_diagnostics_for_config_entry
from tests.typing import ClientSessionGenerator from tests.typing import ClientSessionGenerator
async def test_entry_diagnostics( async def test_entry_diagnostics(
hass: HomeAssistant, hass: HomeAssistant,
config_entry,
hass_client: ClientSessionGenerator, hass_client: ClientSessionGenerator,
setup_config_entry,
snapshot: SnapshotAssertion, snapshot: SnapshotAssertion,
mock_config_entry: MockConfigEntry,
mock_pytile: AsyncMock,
) -> None: ) -> None:
"""Test config entry diagnostics.""" """Test config entry diagnostics."""
await setup_integration(hass, mock_config_entry)
assert ( assert (
await get_diagnostics_for_config_entry(hass, hass_client, config_entry) await get_diagnostics_for_config_entry(hass, hass_client, mock_config_entry)
== snapshot == snapshot
) )