From 745298408a807b129ed197e22bec99bd026a616e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Mon, 4 Oct 2021 17:27:24 +0200 Subject: [PATCH] Rewrite tuya config flow (#57043) Co-authored-by: Martin Hjelmare Co-authored-by: Franck Nijhof --- homeassistant/components/tuya/config_flow.py | 186 ++++++++--------- homeassistant/components/tuya/const.py | 28 ++- homeassistant/components/tuya/strings.json | 25 +-- .../components/tuya/translations/en.json | 73 +------ tests/components/tuya/test_config_flow.py | 195 +++++------------- 5 files changed, 168 insertions(+), 339 deletions(-) diff --git a/homeassistant/components/tuya/config_flow.py b/homeassistant/components/tuya/config_flow.py index 357910b5388..1b439d49007 100644 --- a/homeassistant/components/tuya/config_flow.py +++ b/homeassistant/components/tuya/config_flow.py @@ -1,10 +1,12 @@ -#!/usr/bin/env python3 """Config flow for Tuya.""" +from __future__ import annotations import logging +from typing import Any from tuya_iot import ProjectType, TuyaOpenAPI import voluptuous as vol +from voluptuous.schema_builder import UNDEFINED from homeassistant import config_entries @@ -16,131 +18,123 @@ from .const import ( CONF_ENDPOINT, CONF_PASSWORD, CONF_PROJECT_TYPE, + CONF_REGION, CONF_USERNAME, DOMAIN, - TUYA_APP_TYPE, - TUYA_ENDPOINT, - TUYA_PROJECT_TYPE, + SMARTLIFE_APP, + TUYA_REGIONS, + TUYA_RESPONSE_CODE, + TUYA_RESPONSE_MSG, + TUYA_RESPONSE_PLATFROM_URL, + TUYA_RESPONSE_RESULT, + TUYA_RESPONSE_SUCCESS, + TUYA_SMART_APP, ) -RESULT_SINGLE_INSTANCE = "single_instance_allowed" -RESULT_AUTH_FAILED = "invalid_auth" -TUYA_ENDPOINT_BASE = "https://openapi.tuyacn.com" -TUYA_ENDPOINT_OTHER = "https://openapi.tuyaus.com" -COUNTRY_CODE_CHINA = ["86", "+86", "China"] - _LOGGER = logging.getLogger(__name__) -# Project Type -DATA_SCHEMA_PROJECT_TYPE = vol.Schema( - {vol.Required(CONF_PROJECT_TYPE, default=0): vol.In(TUYA_PROJECT_TYPE)} -) - -# INDUSTY_SOLUTIONS Schema -DATA_SCHEMA_INDUSTRY_SOLUTIONS = vol.Schema( - { - vol.Required(CONF_ENDPOINT): vol.In(TUYA_ENDPOINT), - vol.Required(CONF_ACCESS_ID): str, - vol.Required(CONF_ACCESS_SECRET): str, - vol.Required(CONF_USERNAME): str, - vol.Required(CONF_PASSWORD): str, - } -) - -# SMART_HOME Schema -DATA_SCHEMA_SMART_HOME = vol.Schema( - { - vol.Required(CONF_ACCESS_ID): str, - vol.Required(CONF_ACCESS_SECRET): str, - vol.Required(CONF_APP_TYPE): vol.In(TUYA_APP_TYPE), - vol.Required(CONF_COUNTRY_CODE): str, - vol.Required(CONF_USERNAME): str, - vol.Required(CONF_PASSWORD): str, - } -) - class TuyaConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """Tuya Config Flow.""" - def __init__(self) -> None: - """Init tuya config flow.""" - super().__init__() - self.conf_project_type = None - @staticmethod - def _try_login(user_input): - project_type = ProjectType(user_input[CONF_PROJECT_TYPE]) - api = TuyaOpenAPI( - user_input[CONF_ENDPOINT] - if project_type == ProjectType.INDUSTY_SOLUTIONS - else "", - user_input[CONF_ACCESS_ID], - user_input[CONF_ACCESS_SECRET], - project_type, - ) - api.set_dev_channel("hass") + def _try_login(user_input: dict[str, Any]) -> tuple[dict[Any, Any], dict[str, Any]]: + """Try login.""" + response = {} - if project_type == ProjectType.INDUSTY_SOLUTIONS: - response = api.login(user_input[CONF_USERNAME], user_input[CONF_PASSWORD]) - else: - if user_input[CONF_COUNTRY_CODE] in COUNTRY_CODE_CHINA: - api.endpoint = TUYA_ENDPOINT_BASE + data = { + CONF_ENDPOINT: TUYA_REGIONS[user_input[CONF_REGION]], + CONF_PROJECT_TYPE: ProjectType.INDUSTY_SOLUTIONS, + CONF_ACCESS_ID: user_input[CONF_ACCESS_ID], + CONF_ACCESS_SECRET: user_input[CONF_ACCESS_SECRET], + CONF_USERNAME: user_input[CONF_USERNAME], + CONF_PASSWORD: user_input[CONF_PASSWORD], + CONF_COUNTRY_CODE: user_input[CONF_REGION], + } + + for app_type in ("", TUYA_SMART_APP, SMARTLIFE_APP): + data[CONF_APP_TYPE] = app_type + if data[CONF_APP_TYPE] == "": + data[CONF_PROJECT_TYPE] = ProjectType.INDUSTY_SOLUTIONS else: - api.endpoint = TUYA_ENDPOINT_OTHER + data[CONF_PROJECT_TYPE] = ProjectType.SMART_HOME + + api = TuyaOpenAPI( + endpoint=data[CONF_ENDPOINT], + access_id=data[CONF_ACCESS_ID], + access_secret=data[CONF_ACCESS_SECRET], + project_type=data[CONF_PROJECT_TYPE], + ) + api.set_dev_channel("hass") response = api.login( - user_input[CONF_USERNAME], - user_input[CONF_PASSWORD], - user_input[CONF_COUNTRY_CODE], - user_input[CONF_APP_TYPE], + username=data[CONF_USERNAME], + password=data[CONF_PASSWORD], + country_code=data[CONF_COUNTRY_CODE], + schema=data[CONF_APP_TYPE], ) - if response.get("success", False) and isinstance( - api.token_info.platform_url, str - ): - api.endpoint = api.token_info.platform_url - user_input[CONF_ENDPOINT] = api.token_info.platform_url - _LOGGER.debug("TuyaConfigFlow._try_login finish, response:, %s", response) - return response + _LOGGER.debug("Response %s", response) + + if response.get(TUYA_RESPONSE_SUCCESS, False): + break + + return response, data async def async_step_user(self, user_input=None): """Step user.""" - if user_input is None: - return self.async_show_form( - step_id="user", data_schema=DATA_SCHEMA_PROJECT_TYPE - ) - - self.conf_project_type = user_input[CONF_PROJECT_TYPE] - - return await self.async_step_login() - - async def async_step_login(self, user_input=None): - """Step login.""" errors = {} - if user_input is not None: - assert self.conf_project_type is not None - user_input[CONF_PROJECT_TYPE] = self.conf_project_type + placeholders = {} - response = await self.hass.async_add_executor_job( + if user_input is not None: + response, data = await self.hass.async_add_executor_job( self._try_login, user_input ) - if response.get("success", False): - _LOGGER.debug("TuyaConfigFlow.async_step_user login success") + if response.get(TUYA_RESPONSE_SUCCESS, False): + if endpoint := response.get(TUYA_RESPONSE_RESULT, {}).get( + TUYA_RESPONSE_PLATFROM_URL + ): + data[CONF_ENDPOINT] = endpoint + + data[CONF_PROJECT_TYPE] = data[CONF_PROJECT_TYPE].value + return self.async_create_entry( title=user_input[CONF_USERNAME], - data=user_input, + data=data, ) - errors["base"] = RESULT_AUTH_FAILED + errors["base"] = "login_error" + placeholders = { + TUYA_RESPONSE_CODE: response.get(TUYA_RESPONSE_CODE), + TUYA_RESPONSE_MSG: response.get(TUYA_RESPONSE_MSG), + } - if ProjectType(self.conf_project_type) == ProjectType.SMART_HOME: - return self.async_show_form( - step_id="login", data_schema=DATA_SCHEMA_SMART_HOME, errors=errors - ) + def _schema_default(key: str) -> str | UNDEFINED: + if not user_input: + return UNDEFINED + return user_input[key] return self.async_show_form( - step_id="login", - data_schema=DATA_SCHEMA_INDUSTRY_SOLUTIONS, + step_id="user", + data_schema=vol.Schema( + { + vol.Required( + CONF_REGION, default=_schema_default(CONF_REGION) + ): vol.In(TUYA_REGIONS.keys()), + vol.Required( + CONF_ACCESS_ID, default=_schema_default(CONF_ACCESS_ID) + ): str, + vol.Required( + CONF_ACCESS_SECRET, default=_schema_default(CONF_ACCESS_SECRET) + ): str, + vol.Required( + CONF_USERNAME, default=_schema_default(CONF_USERNAME) + ): str, + vol.Required( + CONF_PASSWORD, default=_schema_default(CONF_PASSWORD) + ): str, + } + ), errors=errors, + description_placeholders=placeholders, ) diff --git a/homeassistant/components/tuya/const.py b/homeassistant/components/tuya/const.py index e259dd9190b..f86180226ee 100644 --- a/homeassistant/components/tuya/const.py +++ b/homeassistant/components/tuya/const.py @@ -9,6 +9,7 @@ CONF_ACCESS_ID = "access_id" CONF_ACCESS_SECRET = "access_secret" CONF_USERNAME = "username" CONF_PASSWORD = "password" +CONF_REGION = "region" CONF_COUNTRY_CODE = "country_code" CONF_APP_TYPE = "tuya_app_type" @@ -19,19 +20,24 @@ TUYA_MQTT_LISTENER = "tuya_mqtt_listener" TUYA_HA_TUYA_MAP = "tuya_ha_tuya_map" TUYA_HA_DEVICES = "tuya_ha_devices" +TUYA_RESPONSE_CODE = "code" +TUYA_RESPONSE_RESULT = "result" +TUYA_RESPONSE_MSG = "msg" +TUYA_RESPONSE_SUCCESS = "success" +TUYA_RESPONSE_PLATFROM_URL = "platform_url" + TUYA_HA_SIGNAL_UPDATE_ENTITY = "tuya_entry_update" -TUYA_ENDPOINT = { - "https://openapi.tuyaus.com": "America", - "https://openapi.tuyacn.com": "China", - "https://openapi.tuyaeu.com": "Europe", - "https://openapi.tuyain.com": "India", - "https://openapi-ueaz.tuyaus.com": "EasternAmerica", - "https://openapi-weaz.tuyaeu.com": "WesternEurope", +TUYA_SMART_APP = "tuyaSmart" +SMARTLIFE_APP = "smartlife" + +TUYA_REGIONS = { + "America": "https://openapi.tuyaus.com", + "China": "https://openapi.tuyacn.com", + "Eastern America": "https://openapi-ueaz.tuyaus.com", + "Europe": "https://openapi.tuyaeu.com", + "India": "https://openapi.tuyain.com", + "Western Europe": "https://openapi-weaz.tuyaeu.com", } -TUYA_PROJECT_TYPE = {1: "Custom Development", 0: "Smart Home PaaS"} - -TUYA_APP_TYPE = {"tuyaSmart": "TuyaSmart", "smartlife": "Smart Life"} - PLATFORMS = ["climate", "fan", "light", "scene", "switch"] diff --git a/homeassistant/components/tuya/strings.json b/homeassistant/components/tuya/strings.json index 91ca045e1f5..044c068ac9c 100644 --- a/homeassistant/components/tuya/strings.json +++ b/homeassistant/components/tuya/strings.json @@ -1,29 +1,20 @@ { "config": { - "flow_title": "Tuya configuration", "step": { - "user":{ - "title":"Tuya Integration", - "data":{ - "tuya_project_type": "Tuya cloud project type" - } - }, - "login": { - "title": "Tuya", - "description": "Enter your Tuya credential", + "user": { + "description": "Enter your Tuya credentials", "data": { - "endpoint": "Availability Zone", - "access_id": "Access ID", - "access_secret": "Access Secret", - "tuya_app_type": "Mobile App", - "country_code": "Country Code", + "region": "Region", + "access_id": "Tuya IoT Access ID", + "access_secret": "Tuya IoT Access Secret", "username": "Account", - "password": "Password" + "password": "[%key:common::config_flow::data::password%]" } } }, "error": { - "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]" + "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]", + "login_error": "Login error ({code}): {msg}" } } } \ No newline at end of file diff --git a/homeassistant/components/tuya/translations/en.json b/homeassistant/components/tuya/translations/en.json index c7aaee977ee..a3630e66406 100644 --- a/homeassistant/components/tuya/translations/en.json +++ b/homeassistant/components/tuya/translations/en.json @@ -1,78 +1,19 @@ { "config": { - "abort": { - "cannot_connect": "Failed to connect", - "invalid_auth": "Invalid authentication", - "single_instance_allowed": "Already configured. Only a single configuration possible." - }, "error": { - "invalid_auth": "Invalid authentication" + "invalid_auth": "Invalid authentication", + "login_error": "Login error ({code}): {msg}" }, - "flow_title": "Tuya configuration", "step": { - "login": { - "data": { - "access_id": "Access ID", - "access_secret": "Access Secret", - "country_code": "Country Code", - "endpoint": "Availability Zone", - "password": "Password", - "tuya_app_type": "Mobile App", - "username": "Account" - }, - "description": "Enter your Tuya credential", - "title": "Tuya" - }, "user": { "data": { - "country_code": "Your account country code (e.g., 1 for USA or 86 for China)", + "access_id": "Tuya IoT Access ID", + "access_secret": "Tuya IoT Access Secret", "password": "Password", - "platform": "The app where your account is registered", - "tuya_project_type": "Tuya cloud project type", - "username": "Username" + "region": "Region", + "username": "Account" }, - "description": "Enter your Tuya credentials.", - "title": "Tuya Integration" - } - } - }, - "options": { - "abort": { - "cannot_connect": "Failed to connect" - }, - "error": { - "dev_multi_type": "Multiple selected devices to configure must be of the same type", - "dev_not_config": "Device type not configurable", - "dev_not_found": "Device not found" - }, - "step": { - "device": { - "data": { - "brightness_range_mode": "Brightness range used by device", - "curr_temp_divider": "Current Temperature value divider (0 = use default)", - "max_kelvin": "Max color temperature supported in kelvin", - "max_temp": "Max target temperature (use min and max = 0 for default)", - "min_kelvin": "Min color temperature supported in kelvin", - "min_temp": "Min target temperature (use min and max = 0 for default)", - "set_temp_divided": "Use divided Temperature value for set temperature command", - "support_color": "Force color support", - "temp_divider": "Temperature values divider (0 = use default)", - "temp_step_override": "Target Temperature step", - "tuya_max_coltemp": "Max color temperature reported by device", - "unit_of_measurement": "Temperature unit used by device" - }, - "description": "Configure options to adjust displayed information for {device_type} device `{device_name}`", - "title": "Configure Tuya Device" - }, - "init": { - "data": { - "discovery_interval": "Discovery device polling interval in seconds", - "list_devices": "Select the devices to configure or leave empty to save configuration", - "query_device": "Select device that will use query method for faster status update", - "query_interval": "Query device polling interval in seconds" - }, - "description": "Do not set pollings interval values too low or the calls will fail generating error message in the log", - "title": "Configure Tuya Options" + "description": "Enter your Tuya credentials" } } } diff --git a/tests/components/tuya/test_config_flow.py b/tests/components/tuya/test_config_flow.py index b01745ee8db..04fb8ebe009 100644 --- a/tests/components/tuya/test_config_flow.py +++ b/tests/components/tuya/test_config_flow.py @@ -1,93 +1,84 @@ """Tests for the Tuya config flow.""" -from unittest.mock import MagicMock, Mock, patch +from __future__ import annotations + +from typing import Any +from unittest.mock import MagicMock, patch import pytest from homeassistant import config_entries, data_entry_flow -from homeassistant.components.tuya.config_flow import RESULT_AUTH_FAILED from homeassistant.components.tuya.const import ( CONF_ACCESS_ID, CONF_ACCESS_SECRET, CONF_APP_TYPE, - CONF_COUNTRY_CODE, CONF_ENDPOINT, CONF_PASSWORD, CONF_PROJECT_TYPE, + CONF_REGION, CONF_USERNAME, DOMAIN, + SMARTLIFE_APP, + TUYA_REGIONS, + TUYA_SMART_APP, ) +from homeassistant.core import HomeAssistant MOCK_SMART_HOME_PROJECT_TYPE = 0 MOCK_INDUSTRY_PROJECT_TYPE = 1 +MOCK_REGION = "Europe" MOCK_ACCESS_ID = "myAccessId" MOCK_ACCESS_SECRET = "myAccessSecret" MOCK_USERNAME = "myUsername" MOCK_PASSWORD = "myPassword" -MOCK_COUNTRY_CODE_BASE = "86" -MOCK_COUNTRY_CODE_OTHER = "1" -MOCK_APP_TYPE = "smartlife" MOCK_ENDPOINT = "https://openapi-ueaz.tuyaus.com" -TUYA_SMART_HOME_PROJECT_DATA = { - CONF_PROJECT_TYPE: MOCK_SMART_HOME_PROJECT_TYPE, -} -TUYA_INDUSTRY_PROJECT_DATA = { - CONF_PROJECT_TYPE: MOCK_INDUSTRY_PROJECT_TYPE, -} - -TUYA_INPUT_INDUSTRY_DATA = { - CONF_ENDPOINT: MOCK_ENDPOINT, +TUYA_INPUT_DATA = { + CONF_REGION: MOCK_REGION, CONF_ACCESS_ID: MOCK_ACCESS_ID, CONF_ACCESS_SECRET: MOCK_ACCESS_SECRET, CONF_USERNAME: MOCK_USERNAME, CONF_PASSWORD: MOCK_PASSWORD, } -TUYA_IMPORT_SMART_HOME_DATA_BASE = { - CONF_ACCESS_ID: MOCK_ACCESS_ID, - CONF_ACCESS_SECRET: MOCK_ACCESS_SECRET, - CONF_USERNAME: MOCK_USERNAME, - CONF_PASSWORD: MOCK_PASSWORD, - CONF_COUNTRY_CODE: MOCK_COUNTRY_CODE_BASE, - CONF_APP_TYPE: MOCK_APP_TYPE, -} - -TUYA_IMPORT_SMART_HOME_DATA_OTHER = { - CONF_ACCESS_ID: MOCK_ACCESS_ID, - CONF_ACCESS_SECRET: MOCK_ACCESS_SECRET, - CONF_USERNAME: MOCK_USERNAME, - CONF_PASSWORD: MOCK_PASSWORD, - CONF_COUNTRY_CODE: MOCK_COUNTRY_CODE_OTHER, - CONF_APP_TYPE: MOCK_APP_TYPE, -} - -TUYA_IMPORT_INDUSTRY_DATA = { - CONF_PROJECT_TYPE: MOCK_SMART_HOME_PROJECT_TYPE, - CONF_ENDPOINT: MOCK_ENDPOINT, - CONF_ACCESS_ID: MOCK_ACCESS_ID, - CONF_ACCESS_SECRET: MOCK_ACCESS_SECRET, - CONF_USERNAME: MOCK_USERNAME, - CONF_PASSWORD: MOCK_PASSWORD, +RESPONSE_SUCCESS = { + "success": True, + "code": 1024, + "result": {"platform_url": MOCK_ENDPOINT}, } +RESPONSE_ERROR = {"success": False, "code": 123, "msg": "Error"} @pytest.fixture(name="tuya") -def tuya_fixture() -> Mock: +def tuya_fixture() -> MagicMock: """Patch libraries.""" with patch("homeassistant.components.tuya.config_flow.TuyaOpenAPI") as tuya: yield tuya @pytest.fixture(name="tuya_setup", autouse=True) -def tuya_setup_fixture(): +def tuya_setup_fixture() -> None: """Mock tuya entry setup.""" with patch("homeassistant.components.tuya.async_setup_entry", return_value=True): yield -async def test_industry_user(hass, tuya): - """Test industry user config.""" +@pytest.mark.parametrize( + "app_type,side_effects, project_type", + [ + ("", [RESPONSE_SUCCESS], 1), + (TUYA_SMART_APP, [RESPONSE_ERROR, RESPONSE_SUCCESS], 0), + (SMARTLIFE_APP, [RESPONSE_ERROR, RESPONSE_ERROR, RESPONSE_SUCCESS], 0), + ], +) +async def test_user_flow( + hass: HomeAssistant, + tuya: MagicMock, + app_type: str, + side_effects: list[dict[str, Any]], + project_type: int, +): + """Test user flow.""" result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_USER} ) @@ -95,17 +86,9 @@ async def test_industry_user(hass, tuya): assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["step_id"] == "user" + tuya().login = MagicMock(side_effect=side_effects) result = await hass.config_entries.flow.async_configure( - result["flow_id"], user_input=TUYA_INDUSTRY_PROJECT_DATA - ) - await hass.async_block_till_done() - - assert result["type"] == data_entry_flow.RESULT_TYPE_FORM - assert result["step_id"] == "login" - - tuya().login = MagicMock(return_value={"success": True, "errorCode": 1024}) - result = await hass.config_entries.flow.async_configure( - result["flow_id"], user_input=TUYA_INPUT_INDUSTRY_DATA + result["flow_id"], user_input=TUYA_INPUT_DATA ) await hass.async_block_till_done() @@ -115,90 +98,10 @@ async def test_industry_user(hass, tuya): assert result["data"][CONF_ACCESS_SECRET] == MOCK_ACCESS_SECRET assert result["data"][CONF_USERNAME] == MOCK_USERNAME assert result["data"][CONF_PASSWORD] == MOCK_PASSWORD - assert not result["result"].unique_id - - -async def test_smart_home_user_base(hass, tuya): - """Test smart home user config base.""" - result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": config_entries.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=TUYA_SMART_HOME_PROJECT_DATA - ) - await hass.async_block_till_done() - - assert result["type"] == data_entry_flow.RESULT_TYPE_FORM - assert result["step_id"] == "login" - - tuya().login = MagicMock(return_value={"success": False, "errorCode": 1024}) - result = await hass.config_entries.flow.async_configure( - result["flow_id"], user_input=TUYA_IMPORT_SMART_HOME_DATA_BASE - ) - await hass.async_block_till_done() - - assert result["errors"]["base"] == RESULT_AUTH_FAILED - - tuya().login = MagicMock(return_value={"success": True, "errorCode": 1024}) - result = await hass.config_entries.flow.async_configure( - result["flow_id"], user_input=TUYA_IMPORT_SMART_HOME_DATA_BASE - ) - await hass.async_block_till_done() - - assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY - assert result["title"] == MOCK_USERNAME - assert result["data"][CONF_ACCESS_ID] == MOCK_ACCESS_ID - assert result["data"][CONF_ACCESS_SECRET] == MOCK_ACCESS_SECRET - assert result["data"][CONF_USERNAME] == MOCK_USERNAME - assert result["data"][CONF_PASSWORD] == MOCK_PASSWORD - assert result["data"][CONF_COUNTRY_CODE] == MOCK_COUNTRY_CODE_BASE - assert result["data"][CONF_APP_TYPE] == MOCK_APP_TYPE - assert not result["result"].unique_id - - -async def test_smart_home_user_other(hass, tuya): - """Test smart home user config other.""" - result = await hass.config_entries.flow.async_init( - DOMAIN, context={"source": config_entries.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=TUYA_SMART_HOME_PROJECT_DATA - ) - await hass.async_block_till_done() - - assert result["type"] == data_entry_flow.RESULT_TYPE_FORM - assert result["step_id"] == "login" - - tuya().login = MagicMock(return_value={"success": False, "errorCode": 1024}) - result = await hass.config_entries.flow.async_configure( - result["flow_id"], user_input=TUYA_IMPORT_SMART_HOME_DATA_OTHER - ) - await hass.async_block_till_done() - - assert result["errors"]["base"] == RESULT_AUTH_FAILED - - tuya().login = MagicMock(return_value={"success": True, "errorCode": 1024}) - result = await hass.config_entries.flow.async_configure( - result["flow_id"], user_input=TUYA_IMPORT_SMART_HOME_DATA_OTHER - ) - await hass.async_block_till_done() - - assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY - assert result["title"] == MOCK_USERNAME - assert result["data"][CONF_ACCESS_ID] == MOCK_ACCESS_ID - assert result["data"][CONF_ACCESS_SECRET] == MOCK_ACCESS_SECRET - assert result["data"][CONF_USERNAME] == MOCK_USERNAME - assert result["data"][CONF_PASSWORD] == MOCK_PASSWORD - assert result["data"][CONF_COUNTRY_CODE] == MOCK_COUNTRY_CODE_OTHER - assert result["data"][CONF_APP_TYPE] == MOCK_APP_TYPE + assert result["data"][CONF_ENDPOINT] == MOCK_ENDPOINT + assert result["data"][CONF_ENDPOINT] != TUYA_REGIONS[TUYA_INPUT_DATA[CONF_REGION]] + assert result["data"][CONF_APP_TYPE] == app_type + assert result["data"][CONF_PROJECT_TYPE] == project_type assert not result["result"].unique_id @@ -212,18 +115,12 @@ async def test_error_on_invalid_credentials(hass, tuya): assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["step_id"] == "user" + tuya().login = MagicMock(return_value=RESPONSE_ERROR) result = await hass.config_entries.flow.async_configure( - result["flow_id"], user_input=TUYA_INDUSTRY_PROJECT_DATA + result["flow_id"], user_input=TUYA_INPUT_DATA ) await hass.async_block_till_done() - assert result["type"] == data_entry_flow.RESULT_TYPE_FORM - assert result["step_id"] == "login" - - tuya().login = MagicMock(return_value={"success": False, "errorCode": 1024}) - result = await hass.config_entries.flow.async_configure( - result["flow_id"], user_input=TUYA_INPUT_INDUSTRY_DATA - ) - await hass.async_block_till_done() - - assert result["errors"]["base"] == RESULT_AUTH_FAILED + assert result["errors"]["base"] == "login_error" + assert result["description_placeholders"]["code"] == RESPONSE_ERROR["code"] + assert result["description_placeholders"]["msg"] == RESPONSE_ERROR["msg"]