855 lines
25 KiB
Python
855 lines
25 KiB
Python
"""Test the Switch config flow."""
|
|
|
|
from typing import Any
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
from pytest_unordered import unordered
|
|
|
|
from homeassistant import config_entries
|
|
from homeassistant.components.template import DOMAIN, async_setup_entry
|
|
from homeassistant.const import STATE_UNAVAILABLE
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.data_entry_flow import FlowResultType
|
|
|
|
from tests.common import MockConfigEntry
|
|
from tests.typing import WebSocketGenerator
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
(
|
|
"template_type",
|
|
"state_template",
|
|
"template_state",
|
|
"input_states",
|
|
"input_attributes",
|
|
"extra_input",
|
|
"extra_options",
|
|
"extra_attrs",
|
|
),
|
|
[
|
|
(
|
|
"binary_sensor",
|
|
"{{ states('binary_sensor.one') == 'on' or states('binary_sensor.two') == 'on' }}",
|
|
"on",
|
|
{"one": "on", "two": "off"},
|
|
{},
|
|
{},
|
|
{},
|
|
{},
|
|
),
|
|
(
|
|
"sensor",
|
|
"{{ float(states('sensor.one')) + float(states('sensor.two')) }}",
|
|
"50.0",
|
|
{"one": "30.0", "two": "20.0"},
|
|
{},
|
|
{},
|
|
{},
|
|
{},
|
|
),
|
|
],
|
|
)
|
|
async def test_config_flow(
|
|
hass: HomeAssistant,
|
|
template_type,
|
|
state_template,
|
|
template_state,
|
|
input_states,
|
|
input_attributes,
|
|
extra_input,
|
|
extra_options,
|
|
extra_attrs,
|
|
) -> None:
|
|
"""Test the config flow."""
|
|
input_entities = ["one", "two"]
|
|
for input_entity in input_entities:
|
|
hass.states.async_set(
|
|
f"{template_type}.{input_entity}",
|
|
input_states[input_entity],
|
|
input_attributes.get(input_entity, {}),
|
|
)
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
assert result["type"] is FlowResultType.MENU
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{"next_step_id": template_type},
|
|
)
|
|
await hass.async_block_till_done()
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["step_id"] == template_type
|
|
|
|
with patch(
|
|
"homeassistant.components.template.async_setup_entry", wraps=async_setup_entry
|
|
) as mock_setup_entry:
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{
|
|
"name": "My template",
|
|
"state": state_template,
|
|
**extra_input,
|
|
},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
|
assert result["title"] == "My template"
|
|
assert result["data"] == {}
|
|
assert result["options"] == {
|
|
"name": "My template",
|
|
"state": state_template,
|
|
"template_type": template_type,
|
|
**extra_options,
|
|
}
|
|
assert len(mock_setup_entry.mock_calls) == 1
|
|
|
|
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
|
|
assert config_entry.data == {}
|
|
assert config_entry.options == {
|
|
"name": "My template",
|
|
"state": state_template,
|
|
"template_type": template_type,
|
|
**extra_options,
|
|
}
|
|
|
|
state = hass.states.get(f"{template_type}.my_template")
|
|
assert state.state == template_state
|
|
for key in extra_attrs:
|
|
assert state.attributes[key] == extra_attrs[key]
|
|
|
|
|
|
def get_suggested(schema, key):
|
|
"""Get suggested value for key in voluptuous schema."""
|
|
for k in schema:
|
|
if k == key:
|
|
if k.description is None or "suggested_value" not in k.description:
|
|
return None
|
|
return k.description["suggested_value"]
|
|
# Wanted key absent from schema
|
|
raise Exception
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
(
|
|
"template_type",
|
|
"old_state_template",
|
|
"new_state_template",
|
|
"template_state",
|
|
"input_states",
|
|
"extra_options",
|
|
"options_options",
|
|
),
|
|
[
|
|
(
|
|
"binary_sensor",
|
|
"{{ states('binary_sensor.one') == 'on' or states('binary_sensor.two') == 'on' }}",
|
|
"{{ states('binary_sensor.one') == 'on' and states('binary_sensor.two') == 'on' }}",
|
|
["on", "off"],
|
|
{"one": "on", "two": "off"},
|
|
{},
|
|
{},
|
|
),
|
|
(
|
|
"sensor",
|
|
"{{ float(states('sensor.one')) + float(states('sensor.two')) }}",
|
|
"{{ float(states('sensor.one')) - float(states('sensor.two')) }}",
|
|
["50.0", "10.0"],
|
|
{"one": "30.0", "two": "20.0"},
|
|
{},
|
|
{},
|
|
),
|
|
],
|
|
)
|
|
async def test_options(
|
|
hass: HomeAssistant,
|
|
template_type,
|
|
old_state_template,
|
|
new_state_template,
|
|
template_state,
|
|
input_states,
|
|
extra_options,
|
|
options_options,
|
|
) -> None:
|
|
"""Test reconfiguring."""
|
|
input_entities = ["one", "two"]
|
|
|
|
for input_entity in input_entities:
|
|
hass.states.async_set(
|
|
f"{template_type}.{input_entity}", input_states[input_entity], {}
|
|
)
|
|
|
|
template_config_entry = MockConfigEntry(
|
|
data={},
|
|
domain=DOMAIN,
|
|
options={
|
|
"name": "My template",
|
|
"state": old_state_template,
|
|
"template_type": template_type,
|
|
**extra_options,
|
|
},
|
|
title="My template",
|
|
)
|
|
template_config_entry.add_to_hass(hass)
|
|
|
|
assert await hass.config_entries.async_setup(template_config_entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get(f"{template_type}.my_template")
|
|
assert state.state == template_state[0]
|
|
|
|
config_entry = hass.config_entries.async_entries(DOMAIN)[0]
|
|
|
|
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["step_id"] == template_type
|
|
assert get_suggested(result["data_schema"].schema, "state") == old_state_template
|
|
assert "name" not in result["data_schema"].schema
|
|
|
|
result = await hass.config_entries.options.async_configure(
|
|
result["flow_id"],
|
|
user_input={"state": new_state_template, **options_options},
|
|
)
|
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
|
assert result["data"] == {
|
|
"name": "My template",
|
|
"state": new_state_template,
|
|
"template_type": template_type,
|
|
**extra_options,
|
|
}
|
|
assert config_entry.data == {}
|
|
assert config_entry.options == {
|
|
"name": "My template",
|
|
"state": new_state_template,
|
|
"template_type": template_type,
|
|
**extra_options,
|
|
}
|
|
assert config_entry.title == "My template"
|
|
|
|
# Check config entry is reloaded with new options
|
|
await hass.async_block_till_done()
|
|
state = hass.states.get(f"{template_type}.my_template")
|
|
assert state.state == template_state[1]
|
|
|
|
# Check we don't get suggestions from another entry
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
assert result["type"] is FlowResultType.MENU
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{"next_step_id": template_type},
|
|
)
|
|
await hass.async_block_till_done()
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["step_id"] == template_type
|
|
|
|
assert get_suggested(result["data_schema"].schema, "name") is None
|
|
assert get_suggested(result["data_schema"].schema, "state") is None
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
(
|
|
"template_type",
|
|
"state_template",
|
|
"extra_user_input",
|
|
"input_states",
|
|
"template_states",
|
|
"extra_attributes",
|
|
"listeners",
|
|
),
|
|
[
|
|
(
|
|
"binary_sensor",
|
|
"{{ states.binary_sensor.one.state == 'on' or states.binary_sensor.two.state == 'on' }}",
|
|
{},
|
|
{"one": "on", "two": "off"},
|
|
["off", "on"],
|
|
[{}, {}],
|
|
[["one", "two"], ["one"]],
|
|
),
|
|
(
|
|
"sensor",
|
|
"{{ float(states('sensor.one'), default='') + float(states('sensor.two'), default='') }}",
|
|
{},
|
|
{"one": "30.0", "two": "20.0"},
|
|
["", STATE_UNAVAILABLE, "50.0"],
|
|
[{}, {}],
|
|
[["one", "two"], ["one", "two"]],
|
|
),
|
|
],
|
|
)
|
|
async def test_config_flow_preview(
|
|
hass: HomeAssistant,
|
|
hass_ws_client: WebSocketGenerator,
|
|
template_type: str,
|
|
state_template: str,
|
|
extra_user_input: dict[str, Any],
|
|
input_states: list[str],
|
|
template_states: str,
|
|
extra_attributes: list[dict[str, Any]],
|
|
listeners: list[list[str]],
|
|
) -> None:
|
|
"""Test the config flow preview."""
|
|
client = await hass_ws_client(hass)
|
|
|
|
input_entities = ["one", "two"]
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
assert result["type"] is FlowResultType.MENU
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{"next_step_id": template_type},
|
|
)
|
|
await hass.async_block_till_done()
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["step_id"] == template_type
|
|
assert result["errors"] is None
|
|
assert result["preview"] == "template"
|
|
|
|
await client.send_json_auto_id(
|
|
{
|
|
"type": "template/start_preview",
|
|
"flow_id": result["flow_id"],
|
|
"flow_type": "config_flow",
|
|
"user_input": {"name": "My template", "state": state_template}
|
|
| extra_user_input,
|
|
}
|
|
)
|
|
msg = await client.receive_json()
|
|
assert msg["success"]
|
|
assert msg["result"] is None
|
|
|
|
msg = await client.receive_json()
|
|
assert msg["event"] == {
|
|
"attributes": {"friendly_name": "My template"} | extra_attributes[0],
|
|
"listeners": {
|
|
"all": False,
|
|
"domains": [],
|
|
"entities": unordered([f"{template_type}.{_id}" for _id in listeners[0]]),
|
|
"time": False,
|
|
},
|
|
"state": template_states[0],
|
|
}
|
|
|
|
for input_entity in input_entities:
|
|
hass.states.async_set(
|
|
f"{template_type}.{input_entity}", input_states[input_entity], {}
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
for template_state in template_states[1:]:
|
|
msg = await client.receive_json()
|
|
assert msg["event"] == {
|
|
"attributes": {"friendly_name": "My template"}
|
|
| extra_attributes[0]
|
|
| extra_attributes[1],
|
|
"listeners": {
|
|
"all": False,
|
|
"domains": [],
|
|
"entities": unordered(
|
|
[f"{template_type}.{_id}" for _id in listeners[1]]
|
|
),
|
|
"time": False,
|
|
},
|
|
"state": template_state,
|
|
}
|
|
assert len(hass.states.async_all()) == 2
|
|
|
|
|
|
EARLY_END_ERROR = "invalid template (TemplateSyntaxError: unexpected 'end of template')"
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("template_type", "state_template", "extra_user_input", "error"),
|
|
[
|
|
("binary_sensor", "{{", {}, {"state": EARLY_END_ERROR}),
|
|
("sensor", "{{", {}, {"state": EARLY_END_ERROR}),
|
|
(
|
|
"sensor",
|
|
"",
|
|
{"device_class": "aqi", "unit_of_measurement": "cats"},
|
|
{
|
|
"unit_of_measurement": (
|
|
"'cats' is not a valid unit for device class 'aqi'; "
|
|
"expected no unit of measurement"
|
|
),
|
|
},
|
|
),
|
|
(
|
|
"sensor",
|
|
"",
|
|
{"device_class": "temperature", "unit_of_measurement": "cats"},
|
|
{
|
|
"unit_of_measurement": (
|
|
"'cats' is not a valid unit for device class 'temperature'; "
|
|
"expected one of 'K', '°C', '°F'"
|
|
),
|
|
},
|
|
),
|
|
(
|
|
"sensor",
|
|
"",
|
|
{"device_class": "timestamp", "state_class": "measurement"},
|
|
{
|
|
"state_class": (
|
|
"'measurement' is not a valid state class for device class "
|
|
"'timestamp'; expected no state class"
|
|
),
|
|
},
|
|
),
|
|
(
|
|
"sensor",
|
|
"",
|
|
{"device_class": "aqi", "state_class": "total"},
|
|
{
|
|
"state_class": (
|
|
"'total' is not a valid state class for device class "
|
|
"'aqi'; expected 'measurement'"
|
|
),
|
|
},
|
|
),
|
|
(
|
|
"sensor",
|
|
"",
|
|
{"device_class": "energy", "state_class": "measurement"},
|
|
{
|
|
"state_class": (
|
|
"'measurement' is not a valid state class for device class "
|
|
"'energy'; expected one of 'total', 'total_increasing'"
|
|
),
|
|
"unit_of_measurement": (
|
|
"'None' is not a valid unit for device class 'energy'; "
|
|
"expected one of 'GJ', 'kWh', 'MJ', 'MWh', 'Wh'"
|
|
),
|
|
},
|
|
),
|
|
],
|
|
)
|
|
async def test_config_flow_preview_bad_input(
|
|
hass: HomeAssistant,
|
|
hass_ws_client: WebSocketGenerator,
|
|
template_type: str,
|
|
state_template: str,
|
|
extra_user_input: dict[str, str],
|
|
error: str,
|
|
) -> None:
|
|
"""Test the config flow preview."""
|
|
client = await hass_ws_client(hass)
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
assert result["type"] is FlowResultType.MENU
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{"next_step_id": template_type},
|
|
)
|
|
await hass.async_block_till_done()
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["step_id"] == template_type
|
|
assert result["errors"] is None
|
|
assert result["preview"] == "template"
|
|
|
|
await client.send_json_auto_id(
|
|
{
|
|
"type": "template/start_preview",
|
|
"flow_id": result["flow_id"],
|
|
"flow_type": "config_flow",
|
|
"user_input": {"name": "My template", "state": state_template}
|
|
| extra_user_input,
|
|
}
|
|
)
|
|
msg = await client.receive_json()
|
|
assert not msg["success"]
|
|
assert msg["error"] == {
|
|
"code": "invalid_user_input",
|
|
"message": error,
|
|
}
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
(
|
|
"template_type",
|
|
"state_template",
|
|
"input_states",
|
|
"template_states",
|
|
"error_events",
|
|
),
|
|
[
|
|
(
|
|
"sensor",
|
|
"{{ float(states('sensor.one')) + float(states('sensor.two')) }}",
|
|
{"one": "30.0", "two": "20.0"},
|
|
["unavailable", "50.0"],
|
|
[
|
|
(
|
|
"ValueError: Template error: float got invalid input 'unknown' "
|
|
"when rendering template '{{ float(states('sensor.one')) + "
|
|
"float(states('sensor.two')) }}' but no default was specified"
|
|
)
|
|
],
|
|
),
|
|
],
|
|
)
|
|
async def test_config_flow_preview_template_startup_error(
|
|
hass: HomeAssistant,
|
|
hass_ws_client: WebSocketGenerator,
|
|
template_type: str,
|
|
state_template: str,
|
|
input_states: dict[str, str],
|
|
template_states: list[str],
|
|
error_events: list[str],
|
|
) -> None:
|
|
"""Test the config flow preview."""
|
|
client = await hass_ws_client(hass)
|
|
|
|
input_entities = ["one", "two"]
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
assert result["type"] is FlowResultType.MENU
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{"next_step_id": template_type},
|
|
)
|
|
await hass.async_block_till_done()
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["step_id"] == template_type
|
|
assert result["errors"] is None
|
|
assert result["preview"] == "template"
|
|
|
|
await client.send_json_auto_id(
|
|
{
|
|
"type": "template/start_preview",
|
|
"flow_id": result["flow_id"],
|
|
"flow_type": "config_flow",
|
|
"user_input": {"name": "My template", "state": state_template},
|
|
}
|
|
)
|
|
msg = await client.receive_json()
|
|
assert msg["type"] == "result"
|
|
assert msg["success"]
|
|
|
|
for error_event in error_events:
|
|
msg = await client.receive_json()
|
|
assert msg["type"] == "event"
|
|
assert msg["event"] == {"error": error_event}
|
|
|
|
msg = await client.receive_json()
|
|
assert msg["type"] == "event"
|
|
assert msg["event"]["state"] == template_states[0]
|
|
|
|
for input_entity in input_entities:
|
|
hass.states.async_set(
|
|
f"{template_type}.{input_entity}", input_states[input_entity], {}
|
|
)
|
|
|
|
msg = await client.receive_json()
|
|
assert msg["type"] == "event"
|
|
assert msg["event"]["state"] == template_states[1]
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
(
|
|
"template_type",
|
|
"state_template",
|
|
"input_states",
|
|
"template_states",
|
|
"error_events",
|
|
),
|
|
[
|
|
(
|
|
"sensor",
|
|
"{{ float(states('sensor.one')) > 30 and undefined_function() }}",
|
|
[{"one": "30.0", "two": "20.0"}, {"one": "35.0", "two": "20.0"}],
|
|
["False", "unavailable"],
|
|
["'undefined_function' is undefined"],
|
|
),
|
|
],
|
|
)
|
|
async def test_config_flow_preview_template_error(
|
|
hass: HomeAssistant,
|
|
hass_ws_client: WebSocketGenerator,
|
|
template_type: str,
|
|
state_template: str,
|
|
input_states: list[dict[str, str]],
|
|
template_states: list[str],
|
|
error_events: list[str],
|
|
) -> None:
|
|
"""Test the config flow preview."""
|
|
client = await hass_ws_client(hass)
|
|
|
|
input_entities = ["one", "two"]
|
|
|
|
for input_entity in input_entities:
|
|
hass.states.async_set(
|
|
f"{template_type}.{input_entity}", input_states[0][input_entity], {}
|
|
)
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
assert result["type"] is FlowResultType.MENU
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{"next_step_id": template_type},
|
|
)
|
|
await hass.async_block_till_done()
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["step_id"] == template_type
|
|
assert result["errors"] is None
|
|
assert result["preview"] == "template"
|
|
|
|
await client.send_json_auto_id(
|
|
{
|
|
"type": "template/start_preview",
|
|
"flow_id": result["flow_id"],
|
|
"flow_type": "config_flow",
|
|
"user_input": {"name": "My template", "state": state_template},
|
|
}
|
|
)
|
|
msg = await client.receive_json()
|
|
assert msg["type"] == "result"
|
|
assert msg["success"]
|
|
|
|
msg = await client.receive_json()
|
|
assert msg["type"] == "event"
|
|
assert msg["event"]["state"] == template_states[0]
|
|
|
|
for input_entity in input_entities:
|
|
hass.states.async_set(
|
|
f"{template_type}.{input_entity}", input_states[1][input_entity], {}
|
|
)
|
|
|
|
for error_event in error_events:
|
|
msg = await client.receive_json()
|
|
assert msg["type"] == "event"
|
|
assert msg["event"] == {"error": error_event}
|
|
|
|
msg = await client.receive_json()
|
|
assert msg["type"] == "event"
|
|
assert msg["event"]["state"] == template_states[1]
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
(
|
|
"template_type",
|
|
"state_template",
|
|
"extra_user_input",
|
|
),
|
|
[
|
|
(
|
|
"sensor",
|
|
"{{ states('sensor.one') }}",
|
|
{"unit_of_measurement": "°C"},
|
|
),
|
|
],
|
|
)
|
|
async def test_config_flow_preview_bad_state(
|
|
hass: HomeAssistant,
|
|
hass_ws_client: WebSocketGenerator,
|
|
template_type: str,
|
|
state_template: str,
|
|
extra_user_input: dict[str, Any],
|
|
) -> None:
|
|
"""Test the config flow preview."""
|
|
client = await hass_ws_client(hass)
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
assert result["type"] is FlowResultType.MENU
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{"next_step_id": template_type},
|
|
)
|
|
await hass.async_block_till_done()
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["step_id"] == template_type
|
|
assert result["errors"] is None
|
|
assert result["preview"] == "template"
|
|
|
|
await client.send_json_auto_id(
|
|
{
|
|
"type": "template/start_preview",
|
|
"flow_id": result["flow_id"],
|
|
"flow_type": "config_flow",
|
|
"user_input": {"name": "My template", "state": state_template}
|
|
| extra_user_input,
|
|
}
|
|
)
|
|
msg = await client.receive_json()
|
|
assert msg["success"]
|
|
assert msg["result"] is None
|
|
|
|
msg = await client.receive_json()
|
|
assert msg["event"] == {
|
|
"error": (
|
|
"Sensor None has device class 'None', state class 'None' unit '°C' "
|
|
"and suggested precision 'None' thus indicating it has a numeric "
|
|
"value; however, it has the non-numeric value: 'unknown' (<class "
|
|
"'str'>)"
|
|
),
|
|
}
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
(
|
|
"template_type",
|
|
"old_state_template",
|
|
"new_state_template",
|
|
"extra_config_flow_data",
|
|
"extra_user_input",
|
|
"input_states",
|
|
"template_state",
|
|
"extra_attributes",
|
|
"listeners",
|
|
),
|
|
[
|
|
(
|
|
"binary_sensor",
|
|
"{{ states('binary_sensor.one') == 'on' or states('binary_sensor.two') == 'on' }}",
|
|
"{{ states('binary_sensor.one') == 'on' and states('binary_sensor.two') == 'on' }}",
|
|
{},
|
|
{},
|
|
{"one": "on", "two": "off"},
|
|
"off",
|
|
{},
|
|
["one", "two"],
|
|
),
|
|
(
|
|
"sensor",
|
|
"{{ float(states('sensor.one')) + float(states('sensor.two')) }}",
|
|
"{{ float(states('sensor.one')) - float(states('sensor.two')) }}",
|
|
{},
|
|
{},
|
|
{"one": "30.0", "two": "20.0"},
|
|
"10.0",
|
|
{},
|
|
["one", "two"],
|
|
),
|
|
],
|
|
)
|
|
async def test_option_flow_preview(
|
|
hass: HomeAssistant,
|
|
hass_ws_client: WebSocketGenerator,
|
|
template_type: str,
|
|
old_state_template: str,
|
|
new_state_template: str,
|
|
extra_config_flow_data: dict[str, Any],
|
|
extra_user_input: dict[str, Any],
|
|
input_states: list[str],
|
|
template_state: str,
|
|
extra_attributes: dict[str, Any],
|
|
listeners: list[str],
|
|
) -> None:
|
|
"""Test the option flow preview."""
|
|
client = await hass_ws_client(hass)
|
|
|
|
input_entities = ["one", "two"]
|
|
|
|
# Setup the config entry
|
|
config_entry = MockConfigEntry(
|
|
data={},
|
|
domain=DOMAIN,
|
|
options={
|
|
"name": "My template",
|
|
"state": old_state_template,
|
|
"template_type": template_type,
|
|
}
|
|
| extra_config_flow_data,
|
|
title="My template",
|
|
)
|
|
config_entry.add_to_hass(hass)
|
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["errors"] is None
|
|
assert result["preview"] == "template"
|
|
|
|
for input_entity in input_entities:
|
|
hass.states.async_set(
|
|
f"{template_type}.{input_entity}", input_states[input_entity], {}
|
|
)
|
|
|
|
await client.send_json_auto_id(
|
|
{
|
|
"type": "template/start_preview",
|
|
"flow_id": result["flow_id"],
|
|
"flow_type": "options_flow",
|
|
"user_input": {"state": new_state_template} | extra_user_input,
|
|
}
|
|
)
|
|
msg = await client.receive_json()
|
|
assert msg["success"]
|
|
assert msg["result"] is None
|
|
|
|
msg = await client.receive_json()
|
|
assert msg["event"] == {
|
|
"attributes": {"friendly_name": "My template"} | extra_attributes,
|
|
"listeners": {
|
|
"all": False,
|
|
"domains": [],
|
|
"entities": unordered([f"{template_type}.{_id}" for _id in listeners]),
|
|
"time": False,
|
|
},
|
|
"state": template_state,
|
|
}
|
|
assert len(hass.states.async_all()) == 3
|
|
|
|
|
|
async def test_option_flow_sensor_preview_config_entry_removed(
|
|
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
|
|
) -> None:
|
|
"""Test the option flow preview where the config entry is removed."""
|
|
client = await hass_ws_client(hass)
|
|
|
|
# Setup the config entry
|
|
config_entry = MockConfigEntry(
|
|
data={},
|
|
domain=DOMAIN,
|
|
options={
|
|
"name": "My template",
|
|
"state": "Hello!",
|
|
"template_type": "sensor",
|
|
},
|
|
title="My template",
|
|
)
|
|
config_entry.add_to_hass(hass)
|
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["errors"] is None
|
|
assert result["preview"] == "template"
|
|
|
|
await hass.config_entries.async_remove(config_entry.entry_id)
|
|
|
|
await client.send_json_auto_id(
|
|
{
|
|
"type": "template/start_preview",
|
|
"flow_id": result["flow_id"],
|
|
"flow_type": "options_flow",
|
|
"user_input": {"state": "Goodbye!"},
|
|
}
|
|
)
|
|
msg = await client.receive_json()
|
|
assert not msg["success"]
|
|
assert msg["error"] == {"code": "home_assistant_error", "message": "Unknown error"}
|