mirror of
https://github.com/home-assistant/core.git
synced 2026-04-17 15:09:02 +02:00
Refactor Vizio tests: shared fixtures, snapshot_platform, reduced parametrize (#167935)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,9 @@ import pytest
|
||||
from pyvizio.api.apps import AppConfig
|
||||
from pyvizio.const import DEVICE_CLASS_SPEAKER, MAX_VOLUME
|
||||
|
||||
from homeassistant.components.vizio.const import DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .const import (
|
||||
ACCESS_TOKEN,
|
||||
APP_LIST,
|
||||
@@ -17,6 +20,8 @@ from .const import (
|
||||
EQ_LIST,
|
||||
INPUT_LIST,
|
||||
INPUT_LIST_WITH_APPS,
|
||||
MOCK_SPEAKER_CONFIG,
|
||||
MOCK_USER_VALID_TV_CONFIG,
|
||||
MODEL,
|
||||
RESPONSE_TOKEN,
|
||||
UNIQUE_ID,
|
||||
@@ -26,6 +31,8 @@ from .const import (
|
||||
MockStartPairingResponse,
|
||||
)
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
class MockInput:
|
||||
"""Mock Vizio device input."""
|
||||
@@ -41,6 +48,33 @@ def get_mock_inputs(input_list) -> list[MockInput]:
|
||||
return [MockInput(device_input) for device_input in input_list]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_tv_config_entry() -> MockConfigEntry:
|
||||
"""Return a mock TV config entry."""
|
||||
return MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=MOCK_USER_VALID_TV_CONFIG,
|
||||
unique_id=UNIQUE_ID,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_speaker_config_entry() -> MockConfigEntry:
|
||||
"""Return a mock speaker config entry."""
|
||||
return MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=MOCK_SPEAKER_CONFIG,
|
||||
unique_id=UNIQUE_ID,
|
||||
)
|
||||
|
||||
|
||||
async def setup_integration(hass: HomeAssistant, config_entry: MockConfigEntry) -> None:
|
||||
"""Add config entry to hass and set up the integration."""
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
@pytest.fixture(name="vizio_get_unique_id", autouse=True)
|
||||
def vizio_get_unique_id_fixture() -> Generator[None]:
|
||||
"""Mock get vizio unique ID."""
|
||||
|
||||
157
tests/components/vizio/snapshots/test_media_player.ambr
Normal file
157
tests/components/vizio/snapshots/test_media_player.ambr
Normal file
@@ -0,0 +1,157 @@
|
||||
# serializer version: 1
|
||||
# name: test_media_player_entity_setup[speaker][media_player.vizio-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'sound_mode_list': list([
|
||||
'Music',
|
||||
'Movie',
|
||||
]),
|
||||
'source_list': list([
|
||||
'HDMI',
|
||||
'USB',
|
||||
'Bluetooth',
|
||||
'AUX',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'media_player',
|
||||
'entity_category': None,
|
||||
'entity_id': 'media_player.vizio',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <MediaPlayerDeviceClass.SPEAKER: 'speaker'>,
|
||||
'original_icon': None,
|
||||
'original_name': None,
|
||||
'platform': 'vizio',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': <MediaPlayerEntityFeature: 85389>,
|
||||
'translation_key': None,
|
||||
'unique_id': 'testid',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_media_player_entity_setup[speaker][media_player.vizio-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'speaker',
|
||||
'friendly_name': 'Vizio',
|
||||
'is_volume_muted': False,
|
||||
'last_non_buffering_state': <MediaPlayerState.ON: 'on'>,
|
||||
'sound_mode': 'Music',
|
||||
'sound_mode_list': list([
|
||||
'Music',
|
||||
'Movie',
|
||||
]),
|
||||
'source': 'HDMI',
|
||||
'source_list': list([
|
||||
'HDMI',
|
||||
'USB',
|
||||
'Bluetooth',
|
||||
'AUX',
|
||||
]),
|
||||
'supported_features': <MediaPlayerEntityFeature: 85389>,
|
||||
'volume_level': 0.4838709677419355,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.vizio',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
# name: test_media_player_entity_setup[tv][media_player.vizio-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'sound_mode_list': list([
|
||||
'Music',
|
||||
'Movie',
|
||||
]),
|
||||
'source_list': list([
|
||||
'HDMI',
|
||||
'USB',
|
||||
'Bluetooth',
|
||||
'AUX',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'media_player',
|
||||
'entity_category': None,
|
||||
'entity_id': 'media_player.vizio',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <MediaPlayerDeviceClass.TV: 'tv'>,
|
||||
'original_icon': None,
|
||||
'original_name': None,
|
||||
'platform': 'vizio',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': <MediaPlayerEntityFeature: 85437>,
|
||||
'translation_key': None,
|
||||
'unique_id': 'testid',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_media_player_entity_setup[tv][media_player.vizio-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'tv',
|
||||
'friendly_name': 'Vizio',
|
||||
'is_volume_muted': False,
|
||||
'last_non_buffering_state': <MediaPlayerState.ON: 'on'>,
|
||||
'sound_mode': 'Music',
|
||||
'sound_mode_list': list([
|
||||
'Music',
|
||||
'Movie',
|
||||
]),
|
||||
'source': 'HDMI',
|
||||
'source_list': list([
|
||||
'HDMI',
|
||||
'USB',
|
||||
'Bluetooth',
|
||||
'AUX',
|
||||
]),
|
||||
'supported_features': <MediaPlayerEntityFeature: 85437>,
|
||||
'volume_level': 0.15,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.vizio',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
103
tests/components/vizio/snapshots/test_remote.ambr
Normal file
103
tests/components/vizio/snapshots/test_remote.ambr
Normal file
@@ -0,0 +1,103 @@
|
||||
# serializer version: 1
|
||||
# name: test_remote_entity_setup[speaker][remote.vizio-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'remote',
|
||||
'entity_category': None,
|
||||
'entity_id': 'remote.vizio',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': None,
|
||||
'platform': 'vizio',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': 'testid',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_remote_entity_setup[speaker][remote.vizio-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Vizio',
|
||||
'supported_features': <RemoteEntityFeature: 0>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'remote.vizio',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
# name: test_remote_entity_setup[tv][remote.vizio-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'remote',
|
||||
'entity_category': None,
|
||||
'entity_id': 'remote.vizio',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': None,
|
||||
'platform': 'vizio',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': 'testid',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_remote_entity_setup[tv][remote.vizio-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Vizio',
|
||||
'supported_features': <RemoteEntityFeature: 0>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'remote.vizio',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
@@ -20,33 +20,22 @@ from homeassistant.const import (
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
|
||||
from .const import (
|
||||
APP_LIST,
|
||||
HOST2,
|
||||
MOCK_SPEAKER_CONFIG,
|
||||
MOCK_USER_VALID_TV_CONFIG,
|
||||
MODEL,
|
||||
NAME2,
|
||||
UNIQUE_ID,
|
||||
VERSION,
|
||||
)
|
||||
from .conftest import setup_integration
|
||||
from .const import APP_LIST, HOST2, MODEL, NAME2, UNIQUE_ID, VERSION
|
||||
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_tv_load_and_unload(hass: HomeAssistant) -> None:
|
||||
async def test_tv_load_and_unload(
|
||||
hass: HomeAssistant, mock_tv_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test loading and unloading TV entry."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, data=MOCK_USER_VALID_TV_CONFIG, unique_id=UNIQUE_ID
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
await setup_integration(hass, mock_tv_config_entry)
|
||||
assert len(hass.states.async_entity_ids(Platform.MEDIA_PLAYER)) == 1
|
||||
assert DATA_APPS in hass.data
|
||||
|
||||
assert await hass.config_entries.async_unload(config_entry.entry_id)
|
||||
assert await hass.config_entries.async_unload(mock_tv_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
entities = hass.states.async_entity_ids(Platform.MEDIA_PLAYER)
|
||||
assert len(entities) == 1
|
||||
@@ -56,17 +45,14 @@ async def test_tv_load_and_unload(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_speaker_load_and_unload(hass: HomeAssistant) -> None:
|
||||
async def test_speaker_load_and_unload(
|
||||
hass: HomeAssistant, mock_speaker_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test loading and unloading speaker entry."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, data=MOCK_SPEAKER_CONFIG, unique_id=UNIQUE_ID
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
await setup_integration(hass, mock_speaker_config_entry)
|
||||
assert len(hass.states.async_entity_ids(Platform.MEDIA_PLAYER)) == 1
|
||||
|
||||
assert await hass.config_entries.async_unload(config_entry.entry_id)
|
||||
assert await hass.config_entries.async_unload(mock_speaker_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
entities = hass.states.async_entity_ids(Platform.MEDIA_PLAYER)
|
||||
assert len(entities) == 1
|
||||
@@ -79,16 +65,12 @@ async def test_speaker_load_and_unload(hass: HomeAssistant) -> None:
|
||||
)
|
||||
async def test_coordinator_update_failure(
|
||||
hass: HomeAssistant,
|
||||
mock_tv_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test coordinator update failure after 10 days."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, data=MOCK_USER_VALID_TV_CONFIG, unique_id=UNIQUE_ID
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
await setup_integration(hass, mock_tv_config_entry)
|
||||
assert len(hass.states.async_entity_ids(Platform.MEDIA_PLAYER)) == 1
|
||||
assert DATA_APPS in hass.data
|
||||
|
||||
@@ -105,12 +87,11 @@ async def test_coordinator_update_failure(
|
||||
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_update")
|
||||
async def test_apps_coordinator_persists_until_last_tv_unloads(
|
||||
hass: HomeAssistant, freezer: FrozenDateTimeFactory
|
||||
hass: HomeAssistant,
|
||||
mock_tv_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test shared apps coordinator is not shut down until the last TV entry unloads."""
|
||||
config_entry_1 = MockConfigEntry(
|
||||
domain=DOMAIN, data=MOCK_USER_VALID_TV_CONFIG, unique_id=UNIQUE_ID
|
||||
)
|
||||
config_entry_2 = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
@@ -121,9 +102,7 @@ async def test_apps_coordinator_persists_until_last_tv_unloads(
|
||||
},
|
||||
unique_id="testid2",
|
||||
)
|
||||
config_entry_1.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry_1.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
await setup_integration(hass, mock_tv_config_entry)
|
||||
|
||||
config_entry_2.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry_2.entry_id)
|
||||
@@ -131,7 +110,7 @@ async def test_apps_coordinator_persists_until_last_tv_unloads(
|
||||
assert len(hass.states.async_entity_ids(Platform.MEDIA_PLAYER)) == 2
|
||||
|
||||
# Unload first TV — coordinator should still be fetching apps
|
||||
assert await hass.config_entries.async_unload(config_entry_1.entry_id)
|
||||
assert await hass.config_entries.async_unload(mock_tv_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
with patch(
|
||||
@@ -159,15 +138,12 @@ async def test_apps_coordinator_persists_until_last_tv_unloads(
|
||||
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_device_registry_model_and_version(
|
||||
hass: HomeAssistant, device_registry: dr.DeviceRegistry
|
||||
hass: HomeAssistant,
|
||||
mock_tv_config_entry: MockConfigEntry,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
) -> None:
|
||||
"""Test that coordinator populates device registry with model and version."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, data=MOCK_USER_VALID_TV_CONFIG, unique_id=UNIQUE_ID
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
await setup_integration(hass, mock_tv_config_entry)
|
||||
|
||||
device = device_registry.async_get_device(identifiers={(DOMAIN, UNIQUE_ID)})
|
||||
assert device is not None
|
||||
@@ -178,15 +154,12 @@ async def test_device_registry_model_and_version(
|
||||
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_bypass_update")
|
||||
async def test_device_registry_without_model_or_version(
|
||||
hass: HomeAssistant, device_registry: dr.DeviceRegistry
|
||||
hass: HomeAssistant,
|
||||
mock_tv_config_entry: MockConfigEntry,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
) -> None:
|
||||
"""Test device registry when model and version are unavailable."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, data=MOCK_USER_VALID_TV_CONFIG, unique_id=UNIQUE_ID
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
await setup_integration(hass, mock_tv_config_entry)
|
||||
|
||||
device = device_registry.async_get_device(identifiers={(DOMAIN, UNIQUE_ID)})
|
||||
assert device is not None
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import AsyncIterator
|
||||
from collections.abc import AsyncIterator, Generator
|
||||
from contextlib import asynccontextmanager
|
||||
from datetime import timedelta
|
||||
from typing import Any
|
||||
@@ -19,6 +19,7 @@ from pyvizio.const import (
|
||||
MAX_VOLUME,
|
||||
UNKNOWN_APP,
|
||||
)
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.media_player import (
|
||||
ATTR_INPUT_SOURCE,
|
||||
@@ -51,10 +52,18 @@ from homeassistant.components.vizio.const import (
|
||||
)
|
||||
from homeassistant.components.vizio.services import SERVICE_UPDATE_SETTING
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_ON, STATE_UNAVAILABLE
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
STATE_UNAVAILABLE,
|
||||
Platform,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from .conftest import setup_integration
|
||||
from .const import (
|
||||
ADDITIONAL_APP_CONFIG,
|
||||
APP_LIST,
|
||||
@@ -68,26 +77,45 @@ from .const import (
|
||||
EQ_LIST,
|
||||
INPUT_LIST,
|
||||
INPUT_LIST_WITH_APPS,
|
||||
MOCK_SPEAKER_CONFIG,
|
||||
MOCK_TV_WITH_ADDITIONAL_APPS_CONFIG,
|
||||
MOCK_TV_WITH_EXCLUDE_CONFIG,
|
||||
MOCK_TV_WITH_INCLUDE_CONFIG,
|
||||
MOCK_USER_VALID_TV_CONFIG,
|
||||
NAME,
|
||||
UNIQUE_ID,
|
||||
UNKNOWN_APP_CONFIG,
|
||||
VOLUME_STEP,
|
||||
)
|
||||
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
|
||||
|
||||
|
||||
async def _add_config_entry_to_hass(
|
||||
hass: HomeAssistant, config_entry: MockConfigEntry
|
||||
@pytest.fixture(autouse=True)
|
||||
def media_player_only() -> Generator[None]:
|
||||
"""Only set up the media_player platform."""
|
||||
with patch(
|
||||
"homeassistant.components.vizio.PLATFORMS",
|
||||
[Platform.MEDIA_PLAYER],
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mock_config_entry_fixture",
|
||||
["mock_tv_config_entry", "mock_speaker_config_entry"],
|
||||
ids=["tv", "speaker"],
|
||||
)
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_media_player_entity_setup(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
snapshot: SnapshotAssertion,
|
||||
mock_config_entry_fixture: str,
|
||||
request: pytest.FixtureRequest,
|
||||
) -> None:
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
"""Test media player entity is created for TV and speaker."""
|
||||
config_entry: MockConfigEntry = request.getfixturevalue(mock_config_entry_fixture)
|
||||
await setup_integration(hass, config_entry)
|
||||
await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id)
|
||||
|
||||
|
||||
def _get_ha_power_state(vizio_power_state: bool) -> str:
|
||||
@@ -143,16 +171,12 @@ async def _cm_for_test_setup_without_apps(
|
||||
yield
|
||||
|
||||
|
||||
async def _test_setup_tv(hass: HomeAssistant, vizio_power_state: bool) -> None:
|
||||
async def _test_setup_tv(
|
||||
hass: HomeAssistant, config_entry: MockConfigEntry, vizio_power_state: bool
|
||||
) -> None:
|
||||
"""Test Vizio TV entity setup."""
|
||||
ha_power_state = _get_ha_power_state(vizio_power_state)
|
||||
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=MOCK_USER_VALID_TV_CONFIG,
|
||||
unique_id=UNIQUE_ID,
|
||||
)
|
||||
|
||||
async with _cm_for_test_setup_without_apps(
|
||||
{
|
||||
"volume": int(MAX_VOLUME[VIZIO_DEVICE_CLASS_TV] / 2),
|
||||
@@ -161,7 +185,7 @@ async def _test_setup_tv(hass: HomeAssistant, vizio_power_state: bool) -> None:
|
||||
},
|
||||
vizio_power_state,
|
||||
):
|
||||
await _add_config_entry_to_hass(hass, config_entry)
|
||||
await setup_integration(hass, config_entry)
|
||||
|
||||
attr = _get_attr_and_assert_base_attr(
|
||||
hass, MediaPlayerDeviceClass.TV, ha_power_state
|
||||
@@ -171,16 +195,12 @@ async def _test_setup_tv(hass: HomeAssistant, vizio_power_state: bool) -> None:
|
||||
assert attr[ATTR_SOUND_MODE] == CURRENT_EQ
|
||||
|
||||
|
||||
async def _test_setup_speaker(hass: HomeAssistant, vizio_power_state: bool) -> None:
|
||||
async def _test_setup_speaker(
|
||||
hass: HomeAssistant, config_entry: MockConfigEntry, vizio_power_state: bool
|
||||
) -> None:
|
||||
"""Test Vizio Speaker entity setup."""
|
||||
ha_power_state = _get_ha_power_state(vizio_power_state)
|
||||
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=MOCK_SPEAKER_CONFIG,
|
||||
unique_id=UNIQUE_ID,
|
||||
)
|
||||
|
||||
audio_settings = {
|
||||
"volume": int(MAX_VOLUME[VIZIO_DEVICE_CLASS_SPEAKER] / 2),
|
||||
"mute": "Off",
|
||||
@@ -191,7 +211,7 @@ async def _test_setup_speaker(hass: HomeAssistant, vizio_power_state: bool) -> N
|
||||
audio_settings,
|
||||
vizio_power_state,
|
||||
):
|
||||
await _add_config_entry_to_hass(hass, config_entry)
|
||||
await setup_integration(hass, config_entry)
|
||||
|
||||
attr = _get_attr_and_assert_base_attr(
|
||||
hass, MediaPlayerDeviceClass.SPEAKER, ha_power_state
|
||||
@@ -203,13 +223,9 @@ async def _test_setup_speaker(hass: HomeAssistant, vizio_power_state: bool) -> N
|
||||
|
||||
@asynccontextmanager
|
||||
async def _cm_for_test_setup_tv_with_apps(
|
||||
hass: HomeAssistant, device_config: dict[str, Any], app_config: dict[str, Any]
|
||||
hass: HomeAssistant, config_entry: MockConfigEntry, app_config: dict[str, Any]
|
||||
) -> AsyncIterator[None]:
|
||||
"""Context manager to setup test for Vizio TV with support for apps."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, data=device_config, unique_id=UNIQUE_ID
|
||||
)
|
||||
|
||||
async with _cm_for_test_setup_without_apps(
|
||||
{"volume": int(MAX_VOLUME[VIZIO_DEVICE_CLASS_TV] / 2), "mute": "Off"},
|
||||
True,
|
||||
@@ -218,7 +234,7 @@ async def _cm_for_test_setup_tv_with_apps(
|
||||
"homeassistant.components.vizio.VizioAsync.get_current_app_config",
|
||||
return_value=AppConfig(**app_config),
|
||||
):
|
||||
await _add_config_entry_to_hass(hass, config_entry)
|
||||
await setup_integration(hass, config_entry)
|
||||
|
||||
attr = _get_attr_and_assert_base_attr(
|
||||
hass, MediaPlayerDeviceClass.TV, STATE_ON
|
||||
@@ -274,57 +290,65 @@ async def _test_service(
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_speaker_on(hass: HomeAssistant) -> None:
|
||||
async def test_speaker_on(
|
||||
hass: HomeAssistant, mock_speaker_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test Vizio Speaker entity setup when on."""
|
||||
await _test_setup_speaker(hass, True)
|
||||
await _test_setup_speaker(hass, mock_speaker_config_entry, True)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_speaker_off(hass: HomeAssistant) -> None:
|
||||
async def test_speaker_off(
|
||||
hass: HomeAssistant, mock_speaker_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test Vizio Speaker entity setup when off."""
|
||||
await _test_setup_speaker(hass, False)
|
||||
await _test_setup_speaker(hass, mock_speaker_config_entry, False)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_init_tv_on(hass: HomeAssistant) -> None:
|
||||
async def test_init_tv_on(
|
||||
hass: HomeAssistant, mock_tv_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test Vizio TV entity setup when on."""
|
||||
await _test_setup_tv(hass, True)
|
||||
await _test_setup_tv(hass, mock_tv_config_entry, True)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_init_tv_off(hass: HomeAssistant) -> None:
|
||||
async def test_init_tv_off(
|
||||
hass: HomeAssistant, mock_tv_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test Vizio TV entity setup when off."""
|
||||
await _test_setup_tv(hass, False)
|
||||
await _test_setup_tv(hass, mock_tv_config_entry, False)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("vizio_cant_connect")
|
||||
async def test_setup_unavailable_speaker(hass: HomeAssistant) -> None:
|
||||
async def test_setup_unavailable_speaker(
|
||||
hass: HomeAssistant, mock_speaker_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test speaker config entry retries setup when device is unavailable."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, data=MOCK_SPEAKER_CONFIG, unique_id=UNIQUE_ID
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
mock_speaker_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_speaker_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert config_entry.state is ConfigEntryState.SETUP_RETRY
|
||||
assert mock_speaker_config_entry.state is ConfigEntryState.SETUP_RETRY
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("vizio_cant_connect")
|
||||
async def test_setup_unavailable_tv(hass: HomeAssistant) -> None:
|
||||
async def test_setup_unavailable_tv(
|
||||
hass: HomeAssistant, mock_tv_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test TV config entry retries setup when device is unavailable."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, data=MOCK_USER_VALID_TV_CONFIG, unique_id=UNIQUE_ID
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
mock_tv_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_tv_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert config_entry.state is ConfigEntryState.SETUP_RETRY
|
||||
assert mock_tv_config_entry.state is ConfigEntryState.SETUP_RETRY
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_services(hass: HomeAssistant) -> None:
|
||||
async def test_services(
|
||||
hass: HomeAssistant, mock_tv_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test all Vizio media player entity services."""
|
||||
await _test_setup_tv(hass, True)
|
||||
await _test_setup_tv(hass, mock_tv_config_entry, True)
|
||||
|
||||
await _test_service(hass, MP_DOMAIN, "pow_on", SERVICE_TURN_ON, None)
|
||||
await _test_service(hass, MP_DOMAIN, "pow_off", SERVICE_TURN_OFF, None)
|
||||
@@ -410,9 +434,11 @@ async def test_services(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_options_update(hass: HomeAssistant) -> None:
|
||||
async def test_options_update(
|
||||
hass: HomeAssistant, mock_speaker_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test when config entry update event fires."""
|
||||
await _test_setup_speaker(hass, True)
|
||||
await _test_setup_speaker(hass, mock_speaker_config_entry, True)
|
||||
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
|
||||
assert config_entry.options
|
||||
new_options = config_entry.options.copy()
|
||||
@@ -432,10 +458,11 @@ async def test_options_update(hass: HomeAssistant) -> None:
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_update_available_to_unavailable(
|
||||
hass: HomeAssistant,
|
||||
mock_speaker_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test device becomes unavailable after being available."""
|
||||
await _test_setup_speaker(hass, True)
|
||||
await _test_setup_speaker(hass, mock_speaker_config_entry, True)
|
||||
|
||||
# Simulate device becoming unreachable
|
||||
with patch(
|
||||
@@ -451,10 +478,11 @@ async def test_update_available_to_unavailable(
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_update_unavailable_to_available(
|
||||
hass: HomeAssistant,
|
||||
mock_speaker_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test device becomes available after being unavailable."""
|
||||
await _test_setup_speaker(hass, True)
|
||||
await _test_setup_speaker(hass, mock_speaker_config_entry, True)
|
||||
|
||||
# First, make device unavailable
|
||||
with patch(
|
||||
@@ -480,11 +508,12 @@ async def test_update_unavailable_to_available(
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update_with_apps")
|
||||
async def test_setup_with_apps(
|
||||
hass: HomeAssistant,
|
||||
mock_tv_config_entry: MockConfigEntry,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test device setup with apps."""
|
||||
async with _cm_for_test_setup_tv_with_apps(
|
||||
hass, MOCK_USER_VALID_TV_CONFIG, CURRENT_APP_CONFIG
|
||||
hass, mock_tv_config_entry, CURRENT_APP_CONFIG
|
||||
):
|
||||
attr = hass.states.get(ENTITY_ID).attributes
|
||||
_assert_source_list_with_apps(list(INPUT_LIST_WITH_APPS + APP_NAME_LIST), attr)
|
||||
@@ -510,9 +539,10 @@ async def test_setup_with_apps_include(
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test device setup with apps and apps["include"] in config."""
|
||||
async with _cm_for_test_setup_tv_with_apps(
|
||||
hass, MOCK_TV_WITH_INCLUDE_CONFIG, CURRENT_APP_CONFIG
|
||||
):
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, data=MOCK_TV_WITH_INCLUDE_CONFIG, unique_id=UNIQUE_ID
|
||||
)
|
||||
async with _cm_for_test_setup_tv_with_apps(hass, config_entry, CURRENT_APP_CONFIG):
|
||||
attr = hass.states.get(ENTITY_ID).attributes
|
||||
_assert_source_list_with_apps([*INPUT_LIST_WITH_APPS, CURRENT_APP], attr)
|
||||
assert CURRENT_APP in attr[ATTR_INPUT_SOURCE_LIST]
|
||||
@@ -527,9 +557,10 @@ async def test_setup_with_apps_exclude(
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test device setup with apps and apps["exclude"] in config."""
|
||||
async with _cm_for_test_setup_tv_with_apps(
|
||||
hass, MOCK_TV_WITH_EXCLUDE_CONFIG, CURRENT_APP_CONFIG
|
||||
):
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, data=MOCK_TV_WITH_EXCLUDE_CONFIG, unique_id=UNIQUE_ID
|
||||
)
|
||||
async with _cm_for_test_setup_tv_with_apps(hass, config_entry, CURRENT_APP_CONFIG):
|
||||
attr = hass.states.get(ENTITY_ID).attributes
|
||||
_assert_source_list_with_apps([*INPUT_LIST_WITH_APPS, CURRENT_APP], attr)
|
||||
assert CURRENT_APP in attr[ATTR_INPUT_SOURCE_LIST]
|
||||
@@ -544,9 +575,12 @@ async def test_setup_with_apps_additional_apps_config(
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test device setup with apps and apps["additional_configs"] in config."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, data=MOCK_TV_WITH_ADDITIONAL_APPS_CONFIG, unique_id=UNIQUE_ID
|
||||
)
|
||||
async with _cm_for_test_setup_tv_with_apps(
|
||||
hass,
|
||||
MOCK_TV_WITH_ADDITIONAL_APPS_CONFIG,
|
||||
config_entry,
|
||||
ADDITIONAL_APP_CONFIG["config"],
|
||||
):
|
||||
attr = hass.states.get(ENTITY_ID).attributes
|
||||
@@ -608,11 +642,12 @@ async def test_setup_with_apps_additional_apps_config(
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update_with_apps")
|
||||
async def test_setup_with_unknown_app_config(
|
||||
hass: HomeAssistant,
|
||||
mock_tv_config_entry: MockConfigEntry,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test device setup with apps where app config returned is unknown."""
|
||||
async with _cm_for_test_setup_tv_with_apps(
|
||||
hass, MOCK_USER_VALID_TV_CONFIG, UNKNOWN_APP_CONFIG
|
||||
hass, mock_tv_config_entry, UNKNOWN_APP_CONFIG
|
||||
):
|
||||
attr = hass.states.get(ENTITY_ID).attributes
|
||||
_assert_source_list_with_apps(list(INPUT_LIST_WITH_APPS + APP_NAME_LIST), attr)
|
||||
@@ -624,11 +659,12 @@ async def test_setup_with_unknown_app_config(
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update_with_apps")
|
||||
async def test_setup_with_no_running_app(
|
||||
hass: HomeAssistant,
|
||||
mock_tv_config_entry: MockConfigEntry,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test device setup with apps where no app is running."""
|
||||
async with _cm_for_test_setup_tv_with_apps(
|
||||
hass, MOCK_USER_VALID_TV_CONFIG, vars(AppConfig())
|
||||
hass, mock_tv_config_entry, vars(AppConfig())
|
||||
):
|
||||
attr = hass.states.get(ENTITY_ID).attributes
|
||||
_assert_source_list_with_apps(list(INPUT_LIST_WITH_APPS + APP_NAME_LIST), attr)
|
||||
@@ -638,19 +674,15 @@ async def test_setup_with_no_running_app(
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_setup_tv_without_mute(hass: HomeAssistant) -> None:
|
||||
async def test_setup_tv_without_mute(
|
||||
hass: HomeAssistant, mock_tv_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test Vizio TV entity setup when mute property isn't returned by Vizio API."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=MOCK_USER_VALID_TV_CONFIG,
|
||||
unique_id=UNIQUE_ID,
|
||||
)
|
||||
|
||||
async with _cm_for_test_setup_without_apps(
|
||||
{"volume": int(MAX_VOLUME[VIZIO_DEVICE_CLASS_TV] / 2)},
|
||||
True,
|
||||
):
|
||||
await _add_config_entry_to_hass(hass, config_entry)
|
||||
await setup_integration(hass, mock_tv_config_entry)
|
||||
|
||||
attr = _get_attr_and_assert_base_attr(hass, MediaPlayerDeviceClass.TV, STATE_ON)
|
||||
_assert_sources_and_volume(attr, VIZIO_DEVICE_CLASS_TV)
|
||||
@@ -661,6 +693,7 @@ async def test_setup_tv_without_mute(hass: HomeAssistant) -> None:
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update_with_apps")
|
||||
async def test_apps_update(
|
||||
hass: HomeAssistant,
|
||||
mock_tv_config_entry: MockConfigEntry,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test device setup with apps where no app is running."""
|
||||
@@ -669,7 +702,7 @@ async def test_apps_update(
|
||||
return_value=None,
|
||||
):
|
||||
async with _cm_for_test_setup_tv_with_apps(
|
||||
hass, MOCK_USER_VALID_TV_CONFIG, vars(AppConfig())
|
||||
hass, mock_tv_config_entry, vars(AppConfig())
|
||||
):
|
||||
# Check source list, remove TV inputs, and verify that the integration is
|
||||
# using the default APPS list
|
||||
@@ -693,14 +726,11 @@ async def test_apps_update(
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update_with_apps_on_input")
|
||||
async def test_vizio_update_with_apps_on_input(hass: HomeAssistant) -> None:
|
||||
async def test_vizio_update_with_apps_on_input(
|
||||
hass: HomeAssistant, mock_tv_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test a vizio TV with apps that is on a TV input."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=MOCK_USER_VALID_TV_CONFIG,
|
||||
unique_id=UNIQUE_ID,
|
||||
)
|
||||
await _add_config_entry_to_hass(hass, config_entry)
|
||||
await setup_integration(hass, mock_tv_config_entry)
|
||||
attr = _get_attr_and_assert_base_attr(hass, MediaPlayerDeviceClass.TV, STATE_ON)
|
||||
# app ID should not be in the attributes
|
||||
assert "app_id" not in attr
|
||||
@@ -709,10 +739,11 @@ async def test_vizio_update_with_apps_on_input(hass: HomeAssistant) -> None:
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_coordinator_update_on_to_off(
|
||||
hass: HomeAssistant,
|
||||
mock_speaker_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test device transitions from on to off during coordinator refresh."""
|
||||
await _test_setup_speaker(hass, True)
|
||||
await _test_setup_speaker(hass, mock_speaker_config_entry, True)
|
||||
attr = _get_attr_and_assert_base_attr(
|
||||
hass, MediaPlayerDeviceClass.SPEAKER, STATE_ON
|
||||
)
|
||||
@@ -738,10 +769,11 @@ async def test_coordinator_update_on_to_off(
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_coordinator_update_off_to_on(
|
||||
hass: HomeAssistant,
|
||||
mock_speaker_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test device transitions from off to on during coordinator refresh."""
|
||||
await _test_setup_speaker(hass, False)
|
||||
await _test_setup_speaker(hass, mock_speaker_config_entry, False)
|
||||
assert hass.states.get(ENTITY_ID).state == STATE_OFF
|
||||
|
||||
# Device turns on
|
||||
@@ -758,10 +790,11 @@ async def test_coordinator_update_off_to_on(
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_sound_mode_feature_toggling(
|
||||
hass: HomeAssistant,
|
||||
mock_speaker_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test sound mode feature is added when present and removed when absent."""
|
||||
await _test_setup_speaker(hass, True)
|
||||
await _test_setup_speaker(hass, mock_speaker_config_entry, True)
|
||||
attr = _get_attr_and_assert_base_attr(
|
||||
hass, MediaPlayerDeviceClass.SPEAKER, STATE_ON
|
||||
)
|
||||
@@ -798,10 +831,11 @@ async def test_sound_mode_feature_toggling(
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_sound_mode_list_cached(
|
||||
hass: HomeAssistant,
|
||||
mock_speaker_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test sound mode list is cached after first retrieval."""
|
||||
await _test_setup_speaker(hass, True)
|
||||
await _test_setup_speaker(hass, mock_speaker_config_entry, True)
|
||||
attr = hass.states.get(ENTITY_ID).attributes
|
||||
assert attr["sound_mode_list"] == EQ_LIST
|
||||
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Generator
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.remote import (
|
||||
ATTR_COMMAND,
|
||||
@@ -13,67 +15,65 @@ from homeassistant.components.remote import (
|
||||
DOMAIN as REMOTE_DOMAIN,
|
||||
SERVICE_SEND_COMMAND,
|
||||
)
|
||||
from homeassistant.components.vizio.const import DOMAIN
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
SERVICE_TURN_OFF,
|
||||
SERVICE_TURN_ON,
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
Platform,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ServiceValidationError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from .const import MOCK_SPEAKER_CONFIG, MOCK_USER_VALID_TV_CONFIG, NAME, UNIQUE_ID
|
||||
from .conftest import setup_integration
|
||||
from .const import NAME
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
|
||||
REMOTE_ENTITY_ID = f"{REMOTE_DOMAIN}.{slugify(NAME)}"
|
||||
|
||||
|
||||
async def _setup_entry(
|
||||
hass: HomeAssistant, config: dict, unique_id: str = UNIQUE_ID
|
||||
) -> MockConfigEntry:
|
||||
"""Set up a Vizio config entry and return it."""
|
||||
config_entry = MockConfigEntry(domain=DOMAIN, data=config, unique_id=unique_id)
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
return config_entry
|
||||
@pytest.fixture(autouse=True)
|
||||
def remote_only() -> Generator[None]:
|
||||
"""Only set up the remote platform."""
|
||||
with patch(
|
||||
"homeassistant.components.vizio.PLATFORMS",
|
||||
[Platform.REMOTE],
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"config",
|
||||
[MOCK_USER_VALID_TV_CONFIG, MOCK_SPEAKER_CONFIG],
|
||||
"config_entry_fixture",
|
||||
["mock_tv_config_entry", "mock_speaker_config_entry"],
|
||||
ids=["tv", "speaker"],
|
||||
)
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_remote_entity_setup(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
config: dict,
|
||||
snapshot: SnapshotAssertion,
|
||||
config_entry_fixture: str,
|
||||
request: pytest.FixtureRequest,
|
||||
) -> None:
|
||||
"""Test remote entity is created for TV and speaker."""
|
||||
await _setup_entry(hass, config)
|
||||
state = hass.states.get(REMOTE_ENTITY_ID)
|
||||
assert state is not None
|
||||
assert state.state == STATE_ON
|
||||
|
||||
entry = entity_registry.async_get(REMOTE_ENTITY_ID)
|
||||
assert entry is not None
|
||||
assert entry.unique_id == UNIQUE_ID
|
||||
config_entry: MockConfigEntry = request.getfixturevalue(config_entry_fixture)
|
||||
await setup_integration(hass, config_entry)
|
||||
await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_remote_is_off_when_device_off(hass: HomeAssistant) -> None:
|
||||
async def test_remote_is_off_when_device_off(
|
||||
hass: HomeAssistant, mock_speaker_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test remote state is off when device is off."""
|
||||
with patch(
|
||||
"homeassistant.components.vizio.VizioAsync.get_power_state",
|
||||
return_value=False,
|
||||
):
|
||||
await _setup_entry(hass, MOCK_SPEAKER_CONFIG)
|
||||
await setup_integration(hass, mock_speaker_config_entry)
|
||||
state = hass.states.get(REMOTE_ENTITY_ID)
|
||||
assert state.state == STATE_OFF
|
||||
|
||||
@@ -86,9 +86,14 @@ async def test_remote_is_off_when_device_off(hass: HomeAssistant) -> None:
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_turn_on_off(hass: HomeAssistant, service: str, mock_method: str) -> None:
|
||||
async def test_turn_on_off(
|
||||
hass: HomeAssistant,
|
||||
mock_speaker_config_entry: MockConfigEntry,
|
||||
service: str,
|
||||
mock_method: str,
|
||||
) -> None:
|
||||
"""Test turning on/off the remote sends the correct power command."""
|
||||
await _setup_entry(hass, MOCK_SPEAKER_CONFIG)
|
||||
await setup_integration(hass, mock_speaker_config_entry)
|
||||
with patch(
|
||||
f"homeassistant.components.vizio.VizioAsync.{mock_method}",
|
||||
) as mock_power:
|
||||
@@ -104,20 +109,20 @@ async def test_turn_on_off(hass: HomeAssistant, service: str, mock_method: str)
|
||||
@pytest.mark.parametrize(
|
||||
("command", "expected_key"),
|
||||
[
|
||||
# Native keys (lowercase tested for a few to verify case-insensitivity)
|
||||
("BACK", "BACK"),
|
||||
("CC_TOGGLE", "CC_TOGGLE"),
|
||||
("ch_up", "CH_UP"),
|
||||
("menu", "MENU"),
|
||||
("SMARTCAST", "SMARTCAST"),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_send_command_tv_valid(
|
||||
hass: HomeAssistant, command: str, expected_key: str
|
||||
hass: HomeAssistant,
|
||||
mock_tv_config_entry: MockConfigEntry,
|
||||
command: str,
|
||||
expected_key: str,
|
||||
) -> None:
|
||||
"""Test send_command resolves valid TV commands."""
|
||||
await _setup_entry(hass, MOCK_USER_VALID_TV_CONFIG)
|
||||
await setup_integration(hass, mock_tv_config_entry)
|
||||
with patch(
|
||||
"homeassistant.components.vizio.VizioAsync.remote",
|
||||
) as mock_remote:
|
||||
@@ -135,9 +140,13 @@ async def test_send_command_tv_valid(
|
||||
|
||||
@pytest.mark.parametrize("command", ["INVALID_KEY", "not_a_key"])
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_send_command_tv_invalid(hass: HomeAssistant, command: str) -> None:
|
||||
async def test_send_command_tv_invalid(
|
||||
hass: HomeAssistant,
|
||||
mock_tv_config_entry: MockConfigEntry,
|
||||
command: str,
|
||||
) -> None:
|
||||
"""Test send_command raises error for invalid TV commands."""
|
||||
await _setup_entry(hass, MOCK_USER_VALID_TV_CONFIG)
|
||||
await setup_integration(hass, mock_tv_config_entry)
|
||||
with pytest.raises(ServiceValidationError):
|
||||
await hass.services.async_call(
|
||||
REMOTE_DOMAIN,
|
||||
@@ -153,25 +162,20 @@ async def test_send_command_tv_invalid(hass: HomeAssistant, command: str) -> Non
|
||||
@pytest.mark.parametrize(
|
||||
("command", "expected_key"),
|
||||
[
|
||||
# Native keys (lowercase tested for a couple)
|
||||
("MUTE_OFF", "MUTE_OFF"),
|
||||
("MUTE_ON", "MUTE_ON"),
|
||||
("MUTE_TOGGLE", "MUTE_TOGGLE"),
|
||||
("pause", "PAUSE"),
|
||||
("PLAY", "PLAY"),
|
||||
("POW_OFF", "POW_OFF"),
|
||||
("POW_ON", "POW_ON"),
|
||||
("POW_TOGGLE", "POW_TOGGLE"),
|
||||
("vol_down", "VOL_DOWN"),
|
||||
("VOL_UP", "VOL_UP"),
|
||||
],
|
||||
)
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_send_command_speaker_valid(
|
||||
hass: HomeAssistant, command: str, expected_key: str
|
||||
hass: HomeAssistant,
|
||||
mock_speaker_config_entry: MockConfigEntry,
|
||||
command: str,
|
||||
expected_key: str,
|
||||
) -> None:
|
||||
"""Test send_command resolves valid speaker commands."""
|
||||
await _setup_entry(hass, MOCK_SPEAKER_CONFIG)
|
||||
await setup_integration(hass, mock_speaker_config_entry)
|
||||
with patch(
|
||||
"homeassistant.components.vizio.VizioAsync.remote",
|
||||
) as mock_remote:
|
||||
@@ -187,21 +191,15 @@ async def test_send_command_speaker_valid(
|
||||
mock_remote.assert_called_once_with(expected_key, log_api_exception=False)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"command",
|
||||
[
|
||||
# TV-only native keys
|
||||
"MENU",
|
||||
"CH_UP",
|
||||
"INPUT_NEXT",
|
||||
# Completely invalid
|
||||
"INVALID_KEY",
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize("command", ["MENU", "CH_UP", "INVALID_KEY"])
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_send_command_speaker_invalid(hass: HomeAssistant, command: str) -> None:
|
||||
async def test_send_command_speaker_invalid(
|
||||
hass: HomeAssistant,
|
||||
mock_speaker_config_entry: MockConfigEntry,
|
||||
command: str,
|
||||
) -> None:
|
||||
"""Test speaker remote rejects TV-only and invalid keys."""
|
||||
await _setup_entry(hass, MOCK_SPEAKER_CONFIG)
|
||||
await setup_integration(hass, mock_speaker_config_entry)
|
||||
with pytest.raises(ServiceValidationError):
|
||||
await hass.services.async_call(
|
||||
REMOTE_DOMAIN,
|
||||
@@ -215,9 +213,11 @@ async def test_send_command_speaker_invalid(hass: HomeAssistant, command: str) -
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_send_command_multiple(hass: HomeAssistant) -> None:
|
||||
async def test_send_command_multiple(
|
||||
hass: HomeAssistant, mock_tv_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test send_command with multiple commands in one call."""
|
||||
await _setup_entry(hass, MOCK_USER_VALID_TV_CONFIG)
|
||||
await setup_integration(hass, mock_tv_config_entry)
|
||||
with patch(
|
||||
"homeassistant.components.vizio.VizioAsync.remote",
|
||||
) as mock_remote:
|
||||
@@ -236,9 +236,11 @@ async def test_send_command_multiple(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_send_command_invalid_skips_valid(hass: HomeAssistant) -> None:
|
||||
async def test_send_command_invalid_skips_valid(
|
||||
hass: HomeAssistant, mock_tv_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test that no commands are sent when one command in the list is invalid."""
|
||||
await _setup_entry(hass, MOCK_USER_VALID_TV_CONFIG)
|
||||
await setup_integration(hass, mock_tv_config_entry)
|
||||
with (
|
||||
patch(
|
||||
"homeassistant.components.vizio.VizioAsync.remote",
|
||||
@@ -258,9 +260,11 @@ async def test_send_command_invalid_skips_valid(hass: HomeAssistant) -> None:
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("vizio_connect", "vizio_update")
|
||||
async def test_send_command_delay_between_repeats(hass: HomeAssistant) -> None:
|
||||
async def test_send_command_delay_between_repeats(
|
||||
hass: HomeAssistant, mock_tv_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test delay is applied between repeats but not after the last one."""
|
||||
await _setup_entry(hass, MOCK_USER_VALID_TV_CONFIG)
|
||||
await setup_integration(hass, mock_tv_config_entry)
|
||||
with (
|
||||
patch(
|
||||
"homeassistant.components.vizio.VizioAsync.remote",
|
||||
|
||||
Reference in New Issue
Block a user