Move apps configuration to options flow for vizio integration (#32543)

* move apps configuration to options flow

* add additional assertion to new test

* add additional assertions for options update

* update docstrings, config validation, and tests based on review
This commit is contained in:
Raman Gupta 2020-03-13 07:16:24 -04:00 committed by GitHub
parent 31d150794d
commit 26d7b2164e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 188 additions and 112 deletions

View File

@ -43,7 +43,8 @@ def _get_config_schema(input_dict: Dict[str, Any] = None) -> vol.Schema:
""" """
Return schema defaults for init step based on user input/config dict. Return schema defaults for init step based on user input/config dict.
Retain info already provided for future form views by setting them as defaults in schema. Retain info already provided for future form views by setting them
as defaults in schema.
""" """
if input_dict is None: if input_dict is None:
input_dict = {} input_dict = {}
@ -70,7 +71,8 @@ def _get_pairing_schema(input_dict: Dict[str, Any] = None) -> vol.Schema:
""" """
Return schema defaults for pairing data based on user input. Return schema defaults for pairing data based on user input.
Retain info already provided for future form views by setting them as defaults in schema. Retain info already provided for future form views by setting
them as defaults in schema.
""" """
if input_dict is None: if input_dict is None:
input_dict = {} input_dict = {}
@ -97,6 +99,16 @@ class VizioOptionsConfigFlow(config_entries.OptionsFlow):
) -> Dict[str, Any]: ) -> Dict[str, Any]:
"""Manage the vizio options.""" """Manage the vizio options."""
if user_input is not None: if user_input is not None:
if user_input.get(CONF_APPS_TO_INCLUDE_OR_EXCLUDE):
user_input[CONF_APPS] = {
user_input[CONF_INCLUDE_OR_EXCLUDE]: user_input[
CONF_APPS_TO_INCLUDE_OR_EXCLUDE
].copy()
}
user_input.pop(CONF_INCLUDE_OR_EXCLUDE)
user_input.pop(CONF_APPS_TO_INCLUDE_OR_EXCLUDE)
return self.async_create_entry(title="", data=user_input) return self.async_create_entry(title="", data=user_input)
options = { options = {
@ -108,6 +120,30 @@ class VizioOptionsConfigFlow(config_entries.OptionsFlow):
): vol.All(vol.Coerce(int), vol.Range(min=1, max=10)) ): vol.All(vol.Coerce(int), vol.Range(min=1, max=10))
} }
if self.config_entry.data[CONF_DEVICE_CLASS] == DEVICE_CLASS_TV:
default_include_or_exclude = (
CONF_EXCLUDE
if self.config_entry.options
and CONF_EXCLUDE in self.config_entry.options.get(CONF_APPS)
else CONF_EXCLUDE
)
options.update(
{
vol.Optional(
CONF_INCLUDE_OR_EXCLUDE,
default=default_include_or_exclude.title(),
): vol.All(
vol.In([CONF_INCLUDE.title(), CONF_EXCLUDE.title()]), vol.Lower
),
vol.Optional(
CONF_APPS_TO_INCLUDE_OR_EXCLUDE,
default=self.config_entry.options.get(CONF_APPS, {}).get(
default_include_or_exclude, []
),
): cv.multi_select(VizioAsync.get_apps_list()),
}
)
return self.async_show_form(step_id="init", data_schema=vol.Schema(options)) return self.async_show_form(step_id="init", data_schema=vol.Schema(options))
@ -135,7 +171,11 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
async def _create_entry_if_unique( async def _create_entry_if_unique(
self, input_dict: Dict[str, Any] self, input_dict: Dict[str, Any]
) -> Dict[str, Any]: ) -> Dict[str, Any]:
"""Check if unique_id doesn't already exist. If it does, abort. If it doesn't, create entry.""" """
Create entry if ID is unique.
If it is, create entry. If it isn't, abort config flow.
"""
# Remove extra keys that will not be used by entry setup # Remove extra keys that will not be used by entry setup
input_dict.pop(CONF_APPS_TO_INCLUDE_OR_EXCLUDE, None) input_dict.pop(CONF_APPS_TO_INCLUDE_OR_EXCLUDE, None)
input_dict.pop(CONF_INCLUDE_OR_EXCLUDE, None) input_dict.pop(CONF_INCLUDE_OR_EXCLUDE, None)
@ -195,13 +235,6 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
) )
self._abort_if_unique_id_configured() self._abort_if_unique_id_configured()
# pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167
if (
user_input[CONF_DEVICE_CLASS] == DEVICE_CLASS_TV
and self.context["source"] != SOURCE_IMPORT
):
self._data = copy.deepcopy(user_input)
return await self.async_step_tv_apps()
return await self._create_entry_if_unique(user_input) return await self._create_entry_if_unique(user_input)
# pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167 # pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167
elif self._must_show_form and self.context["source"] == SOURCE_IMPORT: elif self._must_show_form and self.context["source"] == SOURCE_IMPORT:
@ -250,7 +283,7 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
if not import_config.get(CONF_APPS): if not import_config.get(CONF_APPS):
remove_apps = True remove_apps = True
else: else:
updated_data[CONF_APPS] = import_config[CONF_APPS] updated_options[CONF_APPS] = import_config[CONF_APPS]
if entry.data.get(CONF_VOLUME_STEP) != import_config[CONF_VOLUME_STEP]: if entry.data.get(CONF_VOLUME_STEP) != import_config[CONF_VOLUME_STEP]:
updated_options[CONF_VOLUME_STEP] = import_config[CONF_VOLUME_STEP] updated_options[CONF_VOLUME_STEP] = import_config[CONF_VOLUME_STEP]
@ -261,6 +294,7 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
if remove_apps: if remove_apps:
new_data.pop(CONF_APPS) new_data.pop(CONF_APPS)
new_options.pop(CONF_APPS)
if updated_data: if updated_data:
new_data.update(updated_data) new_data.update(updated_data)
@ -319,7 +353,11 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
async def async_step_pair_tv( async def async_step_pair_tv(
self, user_input: Dict[str, Any] = None self, user_input: Dict[str, Any] = None
) -> Dict[str, Any]: ) -> Dict[str, Any]:
"""Start pairing process and ask user for PIN to complete pairing process.""" """
Start pairing process for TV.
Ask user for PIN to complete pairing process.
"""
errors = {} errors = {}
# Start pairing process if it hasn't already started # Start pairing process if it hasn't already started
@ -382,7 +420,7 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
# If user is pairing via config import, show different message # If user is pairing via config import, show different message
return await self.async_step_pairing_complete_import() return await self.async_step_pairing_complete_import()
return await self.async_step_tv_apps() return await self.async_step_pairing_complete()
# If no data was retrieved, it's assumed that the pairing attempt was not # If no data was retrieved, it's assumed that the pairing attempt was not
# successful # successful
@ -394,43 +432,35 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
errors=errors, errors=errors,
) )
async def async_step_pairing_complete_import( async def _pairing_complete(self, step_id: str) -> Dict[str, Any]:
self, user_input: Dict[str, Any] = None """Handle config flow completion."""
) -> Dict[str, Any]:
"""Complete import config flow by displaying final message to show user access token and give further instructions."""
if not self._must_show_form: if not self._must_show_form:
return await self._create_entry_if_unique(self._data) return await self._create_entry_if_unique(self._data)
self._must_show_form = False self._must_show_form = False
return self.async_show_form( return self.async_show_form(
step_id="pairing_complete_import", step_id=step_id,
data_schema=vol.Schema({}), data_schema=vol.Schema({}),
description_placeholders={"access_token": self._data[CONF_ACCESS_TOKEN]}, description_placeholders={"access_token": self._data[CONF_ACCESS_TOKEN]},
) )
async def async_step_tv_apps( async def async_step_pairing_complete(
self, user_input: Dict[str, Any] = None self, user_input: Dict[str, Any] = None
) -> Dict[str, Any]: ) -> Dict[str, Any]:
"""Handle app configuration to complete TV configuration.""" """
if user_input is not None: Complete non-import sourced config flow.
if user_input.get(CONF_APPS_TO_INCLUDE_OR_EXCLUDE):
# Update stored apps with user entry config keys
self._apps[user_input[CONF_INCLUDE_OR_EXCLUDE].lower()] = user_input[
CONF_APPS_TO_INCLUDE_OR_EXCLUDE
].copy()
return await self._create_entry_if_unique(self._data) Display final message to user confirming pairing.
"""
return await self._pairing_complete("pairing_complete")
return self.async_show_form( async def async_step_pairing_complete_import(
step_id="tv_apps", self, user_input: Dict[str, Any] = None
data_schema=vol.Schema( ) -> Dict[str, Any]:
{ """
vol.Optional( Complete import sourced config flow.
CONF_INCLUDE_OR_EXCLUDE, default=CONF_INCLUDE.title(),
): vol.In([CONF_INCLUDE.title(), CONF_EXCLUDE.title()]), Display final message to user confirming pairing and displaying
vol.Optional(CONF_APPS_TO_INCLUDE_OR_EXCLUDE): cv.multi_select( access token.
VizioAsync.get_apps_list() """
), return await self._pairing_complete("pairing_complete_import")
}
),
)

View File

@ -60,7 +60,6 @@ async def async_setup_entry(
token = config_entry.data.get(CONF_ACCESS_TOKEN) token = config_entry.data.get(CONF_ACCESS_TOKEN)
name = config_entry.data[CONF_NAME] name = config_entry.data[CONF_NAME]
device_class = config_entry.data[CONF_DEVICE_CLASS] device_class = config_entry.data[CONF_DEVICE_CLASS]
conf_apps = config_entry.data.get(CONF_APPS, {})
# If config entry options not set up, set them up, otherwise assign values managed in options # If config entry options not set up, set them up, otherwise assign values managed in options
volume_step = config_entry.options.get( volume_step = config_entry.options.get(
@ -70,6 +69,20 @@ async def async_setup_entry(
params = {} params = {}
if not config_entry.options: if not config_entry.options:
params["options"] = {CONF_VOLUME_STEP: volume_step} params["options"] = {CONF_VOLUME_STEP: volume_step}
include_or_exclude_key = next(
(
key
for key in config_entry.data.get(CONF_APPS, {})
if key in [CONF_INCLUDE, CONF_EXCLUDE]
),
None,
)
if include_or_exclude_key:
params["options"][CONF_APPS] = {
include_or_exclude_key: config_entry.data[CONF_APPS][
include_or_exclude_key
].copy()
}
if not config_entry.data.get(CONF_VOLUME_STEP): if not config_entry.data.get(CONF_VOLUME_STEP):
new_data = config_entry.data.copy() new_data = config_entry.data.copy()
@ -93,9 +106,7 @@ async def async_setup_entry(
_LOGGER.warning("Failed to connect to %s", host) _LOGGER.warning("Failed to connect to %s", host)
raise PlatformNotReady raise PlatformNotReady
entity = VizioDevice( entity = VizioDevice(config_entry, device, name, device_class,)
config_entry, device, name, volume_step, device_class, conf_apps,
)
async_add_entities([entity], update_before_add=True) async_add_entities([entity], update_before_add=True)
@ -108,9 +119,7 @@ class VizioDevice(MediaPlayerDevice):
config_entry: ConfigEntry, config_entry: ConfigEntry,
device: VizioAsync, device: VizioAsync,
name: str, name: str,
volume_step: int,
device_class: str, device_class: str,
conf_apps: Dict[str, List[Any]],
) -> None: ) -> None:
"""Initialize Vizio device.""" """Initialize Vizio device."""
self._config_entry = config_entry self._config_entry = config_entry
@ -119,14 +128,16 @@ class VizioDevice(MediaPlayerDevice):
self._name = name self._name = name
self._state = None self._state = None
self._volume_level = None self._volume_level = None
self._volume_step = volume_step self._volume_step = config_entry.options[CONF_VOLUME_STEP]
self._is_muted = None self._is_muted = None
self._current_input = None self._current_input = None
self._current_app = None self._current_app = None
self._available_inputs = [] self._available_inputs = []
self._available_apps = [] self._available_apps = []
self._conf_apps = conf_apps self._conf_apps = config_entry.options.get(CONF_APPS, {})
self._additional_app_configs = self._conf_apps.get(CONF_ADDITIONAL_CONFIGS, []) self._additional_app_configs = config_entry.data.get(CONF_APPS, {}).get(
CONF_ADDITIONAL_CONFIGS, []
)
self._device_class = device_class self._device_class = device_class
self._supported_commands = SUPPORTED_COMMANDS[device_class] self._supported_commands = SUPPORTED_COMMANDS[device_class]
self._device = device self._device = device
@ -248,6 +259,7 @@ class VizioDevice(MediaPlayerDevice):
async def _async_update_options(self, config_entry: ConfigEntry) -> None: async def _async_update_options(self, config_entry: ConfigEntry) -> None:
"""Update options if the update signal comes from this entity.""" """Update options if the update signal comes from this entity."""
self._volume_step = config_entry.options[CONF_VOLUME_STEP] self._volume_step = config_entry.options[CONF_VOLUME_STEP]
self._conf_apps.update(config_entry.options.get(CONF_APPS, {}))
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Register callbacks when entity is added.""" """Register callbacks when entity is added."""

View File

@ -19,17 +19,13 @@
"pin": "PIN" "pin": "PIN"
} }
}, },
"pairing_complete": {
"title": "Pairing Complete",
"description": "Your Vizio SmartCast device is now connected to Home Assistant."
},
"pairing_complete_import": { "pairing_complete_import": {
"title": "Pairing Complete", "title": "Pairing Complete",
"description": "Your Vizio SmartCast TV is now connected to Home Assistant.\n\nYour Access Token is '**{access_token}**'." "description": "Your Vizio SmartCast TV is now connected to Home Assistant.\n\nYour Access Token is '**{access_token}**'."
},
"tv_apps": {
"title": "Configure Apps for Smart TV",
"description": "If you have a Smart TV, you can optionally filter your source list by choosing which apps to include or exclude in your source list. You can skip this step for TVs that don't support apps.",
"data": {
"include_or_exclude": "Include or Exclude Apps?",
"apps_to_include_or_exclude": "Apps to Include or Exclude"
}
} }
}, },
"error": { "error": {
@ -48,8 +44,11 @@
"step": { "step": {
"init": { "init": {
"title": "Update Vizo SmartCast Options", "title": "Update Vizo SmartCast Options",
"description": "If you have a Smart TV, you can optionally filter your source list by choosing which apps to include or exclude in your source list.",
"data": { "data": {
"volume_step": "Volume Step Size" "volume_step": "Volume Step Size",
"include_or_exclude": "Include or Exclude Apps?",
"apps_to_include_or_exclude": "Apps to Include or Exclude"
} }
} }
} }

View File

@ -9,9 +9,7 @@ from homeassistant.components.media_player import DEVICE_CLASS_SPEAKER, DEVICE_C
from homeassistant.components.vizio.config_flow import _get_config_schema from homeassistant.components.vizio.config_flow import _get_config_schema
from homeassistant.components.vizio.const import ( from homeassistant.components.vizio.const import (
CONF_APPS, CONF_APPS,
CONF_APPS_TO_INCLUDE_OR_EXCLUDE,
CONF_INCLUDE, CONF_INCLUDE,
CONF_INCLUDE_OR_EXCLUDE,
CONF_VOLUME_STEP, CONF_VOLUME_STEP,
DEFAULT_NAME, DEFAULT_NAME,
DEFAULT_VOLUME_STEP, DEFAULT_VOLUME_STEP,
@ -39,6 +37,7 @@ from .const import (
MOCK_PIN_CONFIG, MOCK_PIN_CONFIG,
MOCK_SPEAKER_CONFIG, MOCK_SPEAKER_CONFIG,
MOCK_TV_CONFIG_NO_TOKEN, MOCK_TV_CONFIG_NO_TOKEN,
MOCK_TV_WITH_ADDITIONAL_APPS_CONFIG,
MOCK_TV_WITH_EXCLUDE_CONFIG, MOCK_TV_WITH_EXCLUDE_CONFIG,
MOCK_USER_VALID_TV_CONFIG, MOCK_USER_VALID_TV_CONFIG,
MOCK_ZEROCONF_SERVICE_INFO, MOCK_ZEROCONF_SERVICE_INFO,
@ -95,52 +94,17 @@ async def test_user_flow_all_fields(
result["flow_id"], user_input=MOCK_USER_VALID_TV_CONFIG result["flow_id"], user_input=MOCK_USER_VALID_TV_CONFIG
) )
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "tv_apps"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=MOCK_INCLUDE_APPS
)
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == NAME assert result["title"] == NAME
assert result["data"][CONF_NAME] == NAME assert result["data"][CONF_NAME] == NAME
assert result["data"][CONF_HOST] == HOST assert result["data"][CONF_HOST] == HOST
assert result["data"][CONF_DEVICE_CLASS] == DEVICE_CLASS_TV assert result["data"][CONF_DEVICE_CLASS] == DEVICE_CLASS_TV
assert result["data"][CONF_ACCESS_TOKEN] == ACCESS_TOKEN assert result["data"][CONF_ACCESS_TOKEN] == ACCESS_TOKEN
assert result["data"][CONF_APPS][CONF_INCLUDE] == [CURRENT_APP] assert CONF_APPS not in result["data"]
async def test_user_apps_with_tv( async def test_speaker_options_flow(hass: HomeAssistantType) -> None:
hass: HomeAssistantType, """Test options config flow for speaker."""
vizio_connect: pytest.fixture,
vizio_bypass_setup: pytest.fixture,
) -> None:
"""Test TV can have selected apps during user setup."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}, data=MOCK_IMPORT_VALID_TV_CONFIG
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "tv_apps"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=MOCK_INCLUDE_APPS
)
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == NAME
assert result["data"][CONF_NAME] == NAME
assert result["data"][CONF_HOST] == HOST
assert result["data"][CONF_DEVICE_CLASS] == DEVICE_CLASS_TV
assert result["data"][CONF_ACCESS_TOKEN] == ACCESS_TOKEN
assert result["data"][CONF_APPS][CONF_INCLUDE] == [CURRENT_APP]
assert CONF_APPS_TO_INCLUDE_OR_EXCLUDE not in result["data"]
assert CONF_INCLUDE_OR_EXCLUDE not in result["data"]
async def test_options_flow(hass: HomeAssistantType) -> None:
"""Test options config flow."""
entry = MockConfigEntry(domain=DOMAIN, data=MOCK_SPEAKER_CONFIG) entry = MockConfigEntry(domain=DOMAIN, data=MOCK_SPEAKER_CONFIG)
entry.add_to_hass(hass) entry.add_to_hass(hass)
@ -158,6 +122,58 @@ async def test_options_flow(hass: HomeAssistantType) -> None:
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == "" assert result["title"] == ""
assert result["data"][CONF_VOLUME_STEP] == VOLUME_STEP assert result["data"][CONF_VOLUME_STEP] == VOLUME_STEP
assert CONF_APPS not in result["data"]
async def test_tv_options_flow_no_apps(hass: HomeAssistantType) -> None:
"""Test options config flow for TV without providing apps option."""
entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_VALID_TV_CONFIG)
entry.add_to_hass(hass)
assert not entry.options
result = await hass.config_entries.options.async_init(entry.entry_id, data=None)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "init"
options = {CONF_VOLUME_STEP: VOLUME_STEP}
options.update(MOCK_INCLUDE_NO_APPS)
result = await hass.config_entries.options.async_configure(
result["flow_id"], user_input=options
)
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == ""
assert result["data"][CONF_VOLUME_STEP] == VOLUME_STEP
assert CONF_APPS not in result["data"]
async def test_tv_options_flow_with_apps(hass: HomeAssistantType) -> None:
"""Test options config flow for TV with providing apps option."""
entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_VALID_TV_CONFIG)
entry.add_to_hass(hass)
assert not entry.options
result = await hass.config_entries.options.async_init(entry.entry_id, data=None)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "init"
options = {CONF_VOLUME_STEP: VOLUME_STEP}
options.update(MOCK_INCLUDE_APPS)
result = await hass.config_entries.options.async_configure(
result["flow_id"], user_input=options
)
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == ""
assert result["data"][CONF_VOLUME_STEP] == VOLUME_STEP
assert CONF_APPS in result["data"]
assert result["data"][CONF_APPS] == {CONF_INCLUDE: [CURRENT_APP]}
async def test_user_host_already_configured( async def test_user_host_already_configured(
@ -282,11 +298,9 @@ async def test_user_tv_pairing_no_apps(
) )
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "tv_apps" assert result["step_id"] == "pairing_complete"
result = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(result["flow_id"])
result["flow_id"], user_input=MOCK_INCLUDE_NO_APPS
)
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == NAME assert result["title"] == NAME
@ -427,10 +441,8 @@ async def test_import_flow_update_options(
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "updated_entry" assert result["reason"] == "updated_entry"
assert ( config_entry = hass.config_entries.async_get_entry(entry_id)
hass.config_entries.async_get_entry(entry_id).options[CONF_VOLUME_STEP] assert config_entry.options[CONF_VOLUME_STEP] == VOLUME_STEP + 1
== VOLUME_STEP + 1
)
async def test_import_flow_update_name_and_apps( async def test_import_flow_update_name_and_apps(
@ -461,10 +473,10 @@ async def test_import_flow_update_name_and_apps(
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "updated_entry" assert result["reason"] == "updated_entry"
assert hass.config_entries.async_get_entry(entry_id).data[CONF_NAME] == NAME2 config_entry = hass.config_entries.async_get_entry(entry_id)
assert hass.config_entries.async_get_entry(entry_id).data[CONF_APPS] == { assert config_entry.data[CONF_NAME] == NAME2
CONF_INCLUDE: [CURRENT_APP] assert config_entry.data[CONF_APPS] == {CONF_INCLUDE: [CURRENT_APP]}
} assert config_entry.options[CONF_APPS] == {CONF_INCLUDE: [CURRENT_APP]}
async def test_import_flow_update_remove_apps( async def test_import_flow_update_remove_apps(
@ -482,7 +494,9 @@ async def test_import_flow_update_remove_apps(
assert result["result"].data[CONF_NAME] == NAME assert result["result"].data[CONF_NAME] == NAME
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
entry_id = result["result"].entry_id config_entry = hass.config_entries.async_get_entry(result["result"].entry_id)
assert CONF_APPS in config_entry.data
assert CONF_APPS in config_entry.options
updated_config = MOCK_TV_WITH_EXCLUDE_CONFIG.copy() updated_config = MOCK_TV_WITH_EXCLUDE_CONFIG.copy()
updated_config.pop(CONF_APPS) updated_config.pop(CONF_APPS)
@ -494,7 +508,8 @@ async def test_import_flow_update_remove_apps(
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "updated_entry" assert result["reason"] == "updated_entry"
assert hass.config_entries.async_get_entry(entry_id).data.get(CONF_APPS) is None assert CONF_APPS not in config_entry.data
assert CONF_APPS not in config_entry.options
async def test_import_needs_pairing( async def test_import_needs_pairing(
@ -577,6 +592,26 @@ async def test_import_with_apps_needs_pairing(
assert result["data"][CONF_APPS][CONF_INCLUDE] == [CURRENT_APP] assert result["data"][CONF_APPS][CONF_INCLUDE] == [CURRENT_APP]
async def test_import_flow_additional_configs(
hass: HomeAssistantType,
vizio_connect: pytest.fixture,
vizio_bypass_update: pytest.fixture,
) -> None:
"""Test import config flow with additional configs defined in CONF_APPS."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data=vol.Schema(VIZIO_SCHEMA)(MOCK_TV_WITH_ADDITIONAL_APPS_CONFIG),
)
await hass.async_block_till_done()
assert result["result"].data[CONF_NAME] == NAME
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
config_entry = hass.config_entries.async_get_entry(result["result"].entry_id)
assert CONF_APPS in config_entry.data
assert CONF_APPS not in config_entry.options
async def test_import_error( async def test_import_error(
hass: HomeAssistantType, hass: HomeAssistantType,
vizio_connect: pytest.fixture, vizio_connect: pytest.fixture,