diff --git a/homeassistant/components/enphase_envoy/config_flow.py b/homeassistant/components/enphase_envoy/config_flow.py index 5921de15bde..ee1966d5e51 100644 --- a/homeassistant/components/enphase_envoy/config_flow.py +++ b/homeassistant/components/enphase_envoy/config_flow.py @@ -136,10 +136,6 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): host = (user_input or {}).get(CONF_HOST) or self.ip_address or "" if user_input is not None: - if not self._reauth_entry: - if host in self._async_current_hosts(): - return self.async_abort(reason="already_configured") - try: envoy = await validate_input( self.hass, @@ -170,7 +166,15 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): name = self._async_envoy_name() if self.unique_id: - self._abort_if_unique_id_configured({CONF_HOST: host}) + # If envoy exists in configuration update fields and exit + self._abort_if_unique_id_configured( + { + CONF_HOST: host, + CONF_USERNAME: user_input[CONF_USERNAME], + CONF_PASSWORD: user_input[CONF_PASSWORD], + }, + error="reauth_successful", + ) # CONF_NAME is still set for legacy backwards compatibility return self.async_create_entry( diff --git a/tests/components/enphase_envoy/test_config_flow.py b/tests/components/enphase_envoy/test_config_flow.py index 25517e390ca..9246e882c78 100644 --- a/tests/components/enphase_envoy/test_config_flow.py +++ b/tests/components/enphase_envoy/test_config_flow.py @@ -249,26 +249,66 @@ async def test_zeroconf_token_firmware( } +@pytest.mark.parametrize( + "mock_authenticate", + [ + AsyncMock( + side_effect=[ + None, + EnvoyAuthenticationError("fail authentication"), + None, + ] + ), + ], +) async def test_form_host_already_exists( hass: HomeAssistant, config_entry, setup_enphase_envoy ) -> None: - """Test host already exists.""" + """Test changing credentials for existing host.""" result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_USER} ) assert result["type"] == "form" assert result["errors"] == {} + # existing config + assert config_entry.data["host"] == "1.1.1.1" + assert config_entry.data["username"] == "test-username" + assert config_entry.data["password"] == "test-password" + + # mock failing authentication on first try result2 = await hass.config_entries.flow.async_configure( result["flow_id"], { - "host": "1.1.1.1", + "host": "1.1.1.2", "username": "test-username", - "password": "test-password", + "password": "wrong-password", }, ) - assert result2["type"] == "abort" - assert result2["reason"] == "already_configured" + assert result2["type"] == "form" + assert result2["errors"] == {"base": "invalid_auth"} + + # still original config after failure + assert config_entry.data["host"] == "1.1.1.1" + assert config_entry.data["username"] == "test-username" + assert config_entry.data["password"] == "test-password" + + # mock successful authentication and update of credentials + result3 = await hass.config_entries.flow.async_configure( + result["flow_id"], + { + "host": "1.1.1.2", + "username": "test-username", + "password": "changed-password", + }, + ) + assert result3["type"] == "abort" + assert result3["reason"] == "reauth_successful" + + # updated config with new ip and changed pw + assert config_entry.data["host"] == "1.1.1.2" + assert config_entry.data["username"] == "test-username" + assert config_entry.data["password"] == "changed-password" async def test_zeroconf_serial_already_exists(