async def test_user_flow_minimum_fields_in_zone(hass: HomeAssistant) -> None: """Test user config flow with minimum fields.""" assert await async_setup_component( hass, "zone", { "zone": { CONF_NAME: "Home", CONF_LATITUDE: hass.config.latitude, CONF_LONGITUDE: hass.config.longitude, CONF_RADIUS: 100, } }, ) result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER}) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["step_id"] == "user" result = await hass.config_entries.flow.async_configure( result["flow_id"], user_input=_get_config_schema(hass, SOURCE_USER, MIN_CONFIG)(MIN_CONFIG), ) assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["title"] == f"{DEFAULT_NAME} - Home" assert result["data"][CONF_NAME] == f"{DEFAULT_NAME} - Home" assert result["data"][CONF_API_KEY] == API_KEY assert result["data"][CONF_LATITUDE] == hass.config.latitude assert result["data"][CONF_LONGITUDE] == hass.config.longitude
async def test_options_flow(hass: HomeAssistant) -> None: """Test options config flow for tomorrowio.""" user_config = _get_config_schema(hass, SOURCE_USER)(MIN_CONFIG) entry = MockConfigEntry( domain=DOMAIN, data=user_config, options={CONF_TIMESTEP: DEFAULT_TIMESTEP}, source=SOURCE_USER, unique_id=_get_unique_id(hass, user_config), version=1, ) entry.add_to_hass(hass) await hass.config_entries.async_setup(entry.entry_id) assert entry.options[CONF_TIMESTEP] == DEFAULT_TIMESTEP assert CONF_TIMESTEP not in entry.data 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" result = await hass.config_entries.options.async_configure( result["flow_id"], user_input={CONF_TIMESTEP: 1}) assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["title"] == "" assert result["data"][CONF_TIMESTEP] == 1 assert entry.options[CONF_TIMESTEP] == 1
async def test_user_flow_unknown_exception(hass: HomeAssistant) -> None: """Test user config flow when unknown error occurs.""" with patch( "homeassistant.components.tomorrowio.config_flow.TomorrowioV4.realtime", side_effect=UnknownException, ): result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER}, data=_get_config_schema(hass, SOURCE_USER, MIN_CONFIG)(MIN_CONFIG), ) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["errors"] == {"base": "unknown"}
async def test_user_flow_rate_limited(hass: HomeAssistant) -> None: """Test user config flow when API key is rate limited.""" with patch( "homeassistant.components.tomorrowio.config_flow.TomorrowioV4.realtime", side_effect=RateLimitedException, ): result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER}, data=_get_config_schema(hass, SOURCE_USER, MIN_CONFIG)(MIN_CONFIG), ) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["errors"] == {CONF_API_KEY: "rate_limited"}
async def test_user_flow_invalid_api(hass: HomeAssistant) -> None: """Test user config flow when API key is invalid.""" with patch( "homeassistant.components.tomorrowio.config_flow.TomorrowioV4.realtime", side_effect=InvalidAPIKeyException, ): result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER}, data=_get_config_schema(hass, SOURCE_USER, MIN_CONFIG)(MIN_CONFIG), ) assert result["type"] == data_entry_flow.FlowResultType.FORM assert result["errors"] == {CONF_API_KEY: "invalid_api_key"}
async def test_user_flow_cannot_connect(hass: HomeAssistant) -> None: """Test user config flow when Tomorrow.io can't connect.""" with patch( "homeassistant.components.tomorrowio.config_flow.TomorrowioV4.realtime", side_effect=CantConnectException, ): result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER}, data=_get_config_schema(hass, SOURCE_USER, MIN_CONFIG)(MIN_CONFIG), ) assert result["type"] == data_entry_flow.FlowResultType.FORM assert result["errors"] == {"base": "cannot_connect"}
async def test_load_and_unload(hass: HomeAssistant) -> None: """Test loading and unloading entry.""" data = _get_config_schema(hass, SOURCE_USER)(MIN_CONFIG) data[CONF_NAME] = "test" config_entry = MockConfigEntry( domain=DOMAIN, data=data, options={CONF_TIMESTEP: 1}, unique_id=_get_unique_id(hass, data), version=1, ) config_entry.add_to_hass(hass) assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() assert len(hass.states.async_entity_ids(WEATHER_DOMAIN)) == 1 assert await hass.config_entries.async_remove(config_entry.entry_id) await hass.async_block_till_done() assert len(hass.states.async_entity_ids(WEATHER_DOMAIN)) == 0
async def test_user_flow_minimum_fields(hass: HomeAssistant) -> None: """Test user config flow with minimum fields.""" result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER}) assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["step_id"] == "user" result = await hass.config_entries.flow.async_configure( result["flow_id"], user_input=_get_config_schema(hass, SOURCE_USER, MIN_CONFIG)(MIN_CONFIG), ) assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert result["title"] == DEFAULT_NAME assert result["data"][CONF_NAME] == DEFAULT_NAME assert result["data"][CONF_API_KEY] == API_KEY assert result["data"][CONF_LOCATION][CONF_LATITUDE] == hass.config.latitude assert result["data"][CONF_LOCATION][ CONF_LONGITUDE] == hass.config.longitude
async def test_user_flow_same_unique_ids(hass: HomeAssistant) -> None: """Test user config flow with the same unique ID as an existing entry.""" user_input = _get_config_schema(hass, SOURCE_USER, MIN_CONFIG)(MIN_CONFIG) MockConfigEntry( domain=DOMAIN, data=user_input, options={ CONF_TIMESTEP: DEFAULT_TIMESTEP }, source=SOURCE_USER, unique_id=_get_unique_id(hass, user_input), version=2, ).add_to_hass(hass) result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_USER}, data=user_input, ) assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT assert result["reason"] == "already_configured"
async def _setup(hass: HomeAssistant, sensors: list[str], config: dict[str, Any]) -> State: """Set up entry and return entity state.""" with patch( "homeassistant.util.dt.utcnow", return_value=datetime(2021, 3, 6, 23, 59, 59, tzinfo=dt_util.UTC), ): data = _get_config_schema(hass, SOURCE_USER)(config) data[CONF_NAME] = DEFAULT_NAME config_entry = MockConfigEntry( domain=DOMAIN, data=data, options={CONF_TIMESTEP: DEFAULT_TIMESTEP}, unique_id=_get_unique_id(hass, data), version=1, ) config_entry.add_to_hass(hass) assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() for entity_name in sensors: _enable_entity(hass, CC_SENSOR_ENTITY_ID.format(entity_name)) await hass.async_block_till_done() assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == len(sensors)
async def _setup(hass: HomeAssistant, config: dict[str, Any]) -> State: """Set up entry and return entity state.""" with patch( "homeassistant.util.dt.utcnow", return_value=datetime(2021, 3, 6, 23, 59, 59, tzinfo=dt_util.UTC), ): data = _get_config_schema(hass, SOURCE_USER)(config) data[CONF_NAME] = DEFAULT_NAME config_entry = MockConfigEntry( domain=DOMAIN, data=data, options={CONF_TIMESTEP: DEFAULT_TIMESTEP}, unique_id=_get_unique_id(hass, data), version=1, ) config_entry.add_to_hass(hass) assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() for entity_name in ("hourly", "nowcast"): _enable_entity(hass, f"weather.tomorrow_io_{entity_name}") await hass.async_block_till_done() assert len(hass.states.async_entity_ids(WEATHER_DOMAIN)) == 3 return hass.states.get("weather.tomorrow_io_daily")
async def test_update_intervals(hass: HomeAssistant, tomorrowio_config_entry_update) -> None: """Test coordinator update intervals.""" now = dt_util.utcnow() data = _get_config_schema(hass, SOURCE_USER)(MIN_CONFIG) data[CONF_NAME] = "test" config_entry = MockConfigEntry( domain=DOMAIN, data=data, options={CONF_TIMESTEP: 1}, unique_id=_get_unique_id(hass, data), version=1, ) config_entry.add_to_hass(hass) with patch("homeassistant.helpers.update_coordinator.utcnow", return_value=now): assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() assert len(tomorrowio_config_entry_update.call_args_list) == 1 tomorrowio_config_entry_update.reset_mock() # Before the update interval, no updates yet future = now + timedelta(minutes=30) with patch("homeassistant.helpers.update_coordinator.utcnow", return_value=future): async_fire_time_changed(hass, future) await hass.async_block_till_done() assert len(tomorrowio_config_entry_update.call_args_list) == 0 tomorrowio_config_entry_update.reset_mock() # On the update interval, we get a new update future = now + timedelta(minutes=32) with patch("homeassistant.helpers.update_coordinator.utcnow", return_value=future): async_fire_time_changed(hass, now + timedelta(minutes=32)) await hass.async_block_till_done() assert len(tomorrowio_config_entry_update.call_args_list) == 1 tomorrowio_config_entry_update.reset_mock() # Adding a second config entry should cause the update interval to double config_entry_2 = MockConfigEntry( domain=DOMAIN, data=data, options={CONF_TIMESTEP: 1}, unique_id=f"{_get_unique_id(hass, data)}_1", version=1, ) config_entry_2.add_to_hass(hass) assert await hass.config_entries.async_setup(config_entry_2.entry_id) await hass.async_block_till_done() assert config_entry.data[CONF_API_KEY] == config_entry_2.data[ CONF_API_KEY] # We should get an immediate call once the new config entry is setup for a # partial update assert len(tomorrowio_config_entry_update.call_args_list) == 1 tomorrowio_config_entry_update.reset_mock() # We should get no new calls on our old interval future = now + timedelta(minutes=64) with patch("homeassistant.helpers.update_coordinator.utcnow", return_value=future): async_fire_time_changed(hass, future) await hass.async_block_till_done() assert len(tomorrowio_config_entry_update.call_args_list) == 0 tomorrowio_config_entry_update.reset_mock() # We should get two calls on our new interval, one for each entry future = now + timedelta(minutes=96) with patch("homeassistant.helpers.update_coordinator.utcnow", return_value=future): async_fire_time_changed(hass, future) await hass.async_block_till_done() assert len(tomorrowio_config_entry_update.call_args_list) == 2 tomorrowio_config_entry_update.reset_mock()