From c10f078f2a2153feef85eb5ec299a893111d8a91 Mon Sep 17 00:00:00 2001 From: Manu <4445816+tr4nt0r@users.noreply.github.com> Date: Sat, 9 Nov 2024 16:04:10 +0100 Subject: [PATCH] Add sensors for attribute points (str, int, per, con) to Habitica (#130186) --- .../components/habitica/coordinator.py | 5 + homeassistant/components/habitica/icons.json | 12 + homeassistant/components/habitica/sensor.py | 78 ++++- .../components/habitica/strings.json | 80 +++++ homeassistant/components/habitica/util.py | 50 +++ tests/components/habitica/conftest.py | 5 + .../fixtures/common_buttons_unavailable.json | 19 +- .../components/habitica/fixtures/content.json | 287 ++++++++++++++++++ .../habitica/fixtures/healer_fixture.json | 33 +- .../fixtures/healer_skills_unavailable.json | 33 +- .../fixtures/quest_invitation_off.json | 3 +- .../habitica/fixtures/rogue_fixture.json | 33 +- .../fixtures/rogue_skills_unavailable.json | 33 +- .../fixtures/rogue_stealth_unavailable.json | 33 +- tests/components/habitica/fixtures/user.json | 33 +- .../habitica/fixtures/warrior_fixture.json | 33 +- .../fixtures/warrior_skills_unavailable.json | 33 +- .../habitica/fixtures/wizard_fixture.json | 33 +- .../fixtures/wizard_frost_unavailable.json | 33 +- .../fixtures/wizard_skills_unavailable.json | 33 +- .../habitica/snapshots/test_sensor.ambr | 220 ++++++++++++++ .../components/habitica/test_binary_sensor.py | 6 +- tests/components/habitica/test_button.py | 10 + tests/components/habitica/test_todo.py | 5 + 24 files changed, 1047 insertions(+), 96 deletions(-) create mode 100644 tests/components/habitica/fixtures/content.json diff --git a/homeassistant/components/habitica/coordinator.py b/homeassistant/components/habitica/coordinator.py index cce2c684ba8..f9ffb1b53bd 100644 --- a/homeassistant/components/habitica/coordinator.py +++ b/homeassistant/components/habitica/coordinator.py @@ -51,12 +51,17 @@ class HabiticaDataUpdateCoordinator(DataUpdateCoordinator[HabiticaData]): ), ) self.api = habitipy + self.content: dict[str, Any] = {} async def _async_update_data(self) -> HabiticaData: try: user_response = await self.api.user.get() tasks_response = await self.api.tasks.user.get() tasks_response.extend(await self.api.tasks.user.get(type="completedTodos")) + if not self.content: + self.content = await self.api.content.get( + language=user_response["preferences"]["language"] + ) except ClientResponseError as error: if error.status == HTTPStatus.TOO_MANY_REQUESTS: _LOGGER.debug("Rate limit exceeded, will try again later") diff --git a/homeassistant/components/habitica/icons.json b/homeassistant/components/habitica/icons.json index 0698b85afe1..b2b7e548fd7 100644 --- a/homeassistant/components/habitica/icons.json +++ b/homeassistant/components/habitica/icons.json @@ -126,6 +126,18 @@ }, "rewards": { "default": "mdi:treasure-chest" + }, + "strength": { + "default": "mdi:arm-flex-outline" + }, + "intelligence": { + "default": "mdi:head-snowflake-outline" + }, + "perception": { + "default": "mdi:eye-outline" + }, + "constitution": { + "default": "mdi:run-fast" } }, "switch": { diff --git a/homeassistant/components/habitica/sensor.py b/homeassistant/components/habitica/sensor.py index 77356f88265..3b2395ecc52 100644 --- a/homeassistant/components/habitica/sensor.py +++ b/homeassistant/components/habitica/sensor.py @@ -27,7 +27,7 @@ from homeassistant.helpers.typing import StateType from .const import DOMAIN, UNIT_TASKS from .entity import HabiticaBase from .types import HabiticaConfigEntry -from .util import entity_used_in +from .util import entity_used_in, get_attribute_points, get_attributes_total _LOGGER = logging.getLogger(__name__) @@ -36,7 +36,10 @@ _LOGGER = logging.getLogger(__name__) class HabitipySensorEntityDescription(SensorEntityDescription): """Habitipy Sensor Description.""" - value_fn: Callable[[dict[str, Any]], StateType] + value_fn: Callable[[dict[str, Any], dict[str, Any]], StateType] + attributes_fn: ( + Callable[[dict[str, Any], dict[str, Any]], dict[str, Any] | None] | None + ) = None @dataclass(kw_only=True, frozen=True) @@ -65,76 +68,80 @@ class HabitipySensorEntity(StrEnum): REWARDS = "rewards" GEMS = "gems" TRINKETS = "trinkets" + STRENGTH = "strength" + INTELLIGENCE = "intelligence" + CONSTITUTION = "constitution" + PERCEPTION = "perception" SENSOR_DESCRIPTIONS: tuple[HabitipySensorEntityDescription, ...] = ( HabitipySensorEntityDescription( key=HabitipySensorEntity.DISPLAY_NAME, translation_key=HabitipySensorEntity.DISPLAY_NAME, - value_fn=lambda user: user.get("profile", {}).get("name"), + value_fn=lambda user, _: user.get("profile", {}).get("name"), ), HabitipySensorEntityDescription( key=HabitipySensorEntity.HEALTH, translation_key=HabitipySensorEntity.HEALTH, native_unit_of_measurement="HP", suggested_display_precision=0, - value_fn=lambda user: user.get("stats", {}).get("hp"), + value_fn=lambda user, _: user.get("stats", {}).get("hp"), ), HabitipySensorEntityDescription( key=HabitipySensorEntity.HEALTH_MAX, translation_key=HabitipySensorEntity.HEALTH_MAX, native_unit_of_measurement="HP", entity_registry_enabled_default=False, - value_fn=lambda user: user.get("stats", {}).get("maxHealth"), + value_fn=lambda user, _: user.get("stats", {}).get("maxHealth"), ), HabitipySensorEntityDescription( key=HabitipySensorEntity.MANA, translation_key=HabitipySensorEntity.MANA, native_unit_of_measurement="MP", suggested_display_precision=0, - value_fn=lambda user: user.get("stats", {}).get("mp"), + value_fn=lambda user, _: user.get("stats", {}).get("mp"), ), HabitipySensorEntityDescription( key=HabitipySensorEntity.MANA_MAX, translation_key=HabitipySensorEntity.MANA_MAX, native_unit_of_measurement="MP", - value_fn=lambda user: user.get("stats", {}).get("maxMP"), + value_fn=lambda user, _: user.get("stats", {}).get("maxMP"), ), HabitipySensorEntityDescription( key=HabitipySensorEntity.EXPERIENCE, translation_key=HabitipySensorEntity.EXPERIENCE, native_unit_of_measurement="XP", - value_fn=lambda user: user.get("stats", {}).get("exp"), + value_fn=lambda user, _: user.get("stats", {}).get("exp"), ), HabitipySensorEntityDescription( key=HabitipySensorEntity.EXPERIENCE_MAX, translation_key=HabitipySensorEntity.EXPERIENCE_MAX, native_unit_of_measurement="XP", - value_fn=lambda user: user.get("stats", {}).get("toNextLevel"), + value_fn=lambda user, _: user.get("stats", {}).get("toNextLevel"), ), HabitipySensorEntityDescription( key=HabitipySensorEntity.LEVEL, translation_key=HabitipySensorEntity.LEVEL, - value_fn=lambda user: user.get("stats", {}).get("lvl"), + value_fn=lambda user, _: user.get("stats", {}).get("lvl"), ), HabitipySensorEntityDescription( key=HabitipySensorEntity.GOLD, translation_key=HabitipySensorEntity.GOLD, native_unit_of_measurement="GP", suggested_display_precision=2, - value_fn=lambda user: user.get("stats", {}).get("gp"), + value_fn=lambda user, _: user.get("stats", {}).get("gp"), ), HabitipySensorEntityDescription( key=HabitipySensorEntity.CLASS, translation_key=HabitipySensorEntity.CLASS, - value_fn=lambda user: user.get("stats", {}).get("class"), + value_fn=lambda user, _: user.get("stats", {}).get("class"), device_class=SensorDeviceClass.ENUM, options=["warrior", "healer", "wizard", "rogue"], ), HabitipySensorEntityDescription( key=HabitipySensorEntity.GEMS, translation_key=HabitipySensorEntity.GEMS, - value_fn=lambda user: user.get("balance", 0) * 4, + value_fn=lambda user, _: user.get("balance", 0) * 4, suggested_display_precision=0, native_unit_of_measurement="gems", ), @@ -142,7 +149,7 @@ SENSOR_DESCRIPTIONS: tuple[HabitipySensorEntityDescription, ...] = ( key=HabitipySensorEntity.TRINKETS, translation_key=HabitipySensorEntity.TRINKETS, value_fn=( - lambda user: user.get("purchased", {}) + lambda user, _: user.get("purchased", {}) .get("plan", {}) .get("consecutive", {}) .get("trinkets", 0) @@ -150,6 +157,38 @@ SENSOR_DESCRIPTIONS: tuple[HabitipySensorEntityDescription, ...] = ( suggested_display_precision=0, native_unit_of_measurement="⧖", ), + HabitipySensorEntityDescription( + key=HabitipySensorEntity.STRENGTH, + translation_key=HabitipySensorEntity.STRENGTH, + value_fn=lambda user, content: get_attributes_total(user, content, "str"), + attributes_fn=lambda user, content: get_attribute_points(user, content, "str"), + suggested_display_precision=0, + native_unit_of_measurement="STR", + ), + HabitipySensorEntityDescription( + key=HabitipySensorEntity.INTELLIGENCE, + translation_key=HabitipySensorEntity.INTELLIGENCE, + value_fn=lambda user, content: get_attributes_total(user, content, "int"), + attributes_fn=lambda user, content: get_attribute_points(user, content, "int"), + suggested_display_precision=0, + native_unit_of_measurement="INT", + ), + HabitipySensorEntityDescription( + key=HabitipySensorEntity.PERCEPTION, + translation_key=HabitipySensorEntity.PERCEPTION, + value_fn=lambda user, content: get_attributes_total(user, content, "per"), + attributes_fn=lambda user, content: get_attribute_points(user, content, "per"), + suggested_display_precision=0, + native_unit_of_measurement="PER", + ), + HabitipySensorEntityDescription( + key=HabitipySensorEntity.CONSTITUTION, + translation_key=HabitipySensorEntity.CONSTITUTION, + value_fn=lambda user, content: get_attributes_total(user, content, "con"), + attributes_fn=lambda user, content: get_attribute_points(user, content, "con"), + suggested_display_precision=0, + native_unit_of_measurement="CON", + ), ) @@ -243,7 +282,16 @@ class HabitipySensor(HabiticaBase, SensorEntity): def native_value(self) -> StateType: """Return the state of the device.""" - return self.entity_description.value_fn(self.coordinator.data.user) + return self.entity_description.value_fn( + self.coordinator.data.user, self.coordinator.content + ) + + @property + def extra_state_attributes(self) -> dict[str, float | None] | None: + """Return entity specific state attributes.""" + if func := self.entity_description.attributes_fn: + return func(self.coordinator.data.user, self.coordinator.content) + return None class HabitipyTaskSensor(HabiticaBase, SensorEntity): diff --git a/homeassistant/components/habitica/strings.json b/homeassistant/components/habitica/strings.json index f7d2f20b8f9..5e453c61037 100644 --- a/homeassistant/components/habitica/strings.json +++ b/homeassistant/components/habitica/strings.json @@ -164,6 +164,86 @@ }, "rewards": { "name": "Rewards" + }, + "strength": { + "name": "Strength", + "state_attributes": { + "level": { + "name": "[%key:component::habitica::entity::sensor::level::name%]" + }, + "equipment": { + "name": "Battle gear" + }, + "class": { + "name": "Class equip bonus" + }, + "allocated": { + "name": "Allocated attribute points" + }, + "buffs": { + "name": "Buffs" + } + } + }, + "intelligence": { + "name": "Intelligence", + "state_attributes": { + "level": { + "name": "[%key:component::habitica::entity::sensor::level::name%]" + }, + "equipment": { + "name": "[%key:component::habitica::entity::sensor::strength::state_attributes::equipment::name%]" + }, + "class": { + "name": "[%key:component::habitica::entity::sensor::strength::state_attributes::class::name%]" + }, + "allocated": { + "name": "[%key:component::habitica::entity::sensor::strength::state_attributes::allocated::name%]" + }, + "buffs": { + "name": "[%key:component::habitica::entity::sensor::strength::state_attributes::buffs::name%]" + } + } + }, + "perception": { + "name": "Perception", + "state_attributes": { + "level": { + "name": "[%key:component::habitica::entity::sensor::level::name%]" + }, + "equipment": { + "name": "[%key:component::habitica::entity::sensor::strength::state_attributes::equipment::name%]" + }, + "class": { + "name": "[%key:component::habitica::entity::sensor::strength::state_attributes::class::name%]" + }, + "allocated": { + "name": "[%key:component::habitica::entity::sensor::strength::state_attributes::allocated::name%]" + }, + "buffs": { + "name": "[%key:component::habitica::entity::sensor::strength::state_attributes::buffs::name%]" + } + } + }, + "constitution": { + "name": "Constitution", + "state_attributes": { + "level": { + "name": "[%key:component::habitica::entity::sensor::level::name%]" + }, + "equipment": { + "name": "[%key:component::habitica::entity::sensor::strength::state_attributes::equipment::name%]" + }, + "class": { + "name": "[%key:component::habitica::entity::sensor::strength::state_attributes::class::name%]" + }, + "allocated": { + "name": "[%key:component::habitica::entity::sensor::strength::state_attributes::allocated::name%]" + }, + "buffs": { + "name": "[%key:component::habitica::entity::sensor::strength::state_attributes::buffs::name%]" + } + } } }, "switch": { diff --git a/homeassistant/components/habitica/util.py b/homeassistant/components/habitica/util.py index 93a7c234a5d..03acb08baf9 100644 --- a/homeassistant/components/habitica/util.py +++ b/homeassistant/components/habitica/util.py @@ -3,6 +3,7 @@ from __future__ import annotations import datetime +from math import floor from typing import TYPE_CHECKING, Any from dateutil.rrule import ( @@ -139,3 +140,52 @@ def get_recurrence_rule(recurrence: rrule) -> str: """ return str(recurrence).split("RRULE:")[1] + + +def get_attribute_points( + user: dict[str, Any], content: dict[str, Any], attribute: str +) -> dict[str, float]: + """Get modifiers contributing to strength attribute.""" + + gear_set = { + "weapon", + "armor", + "head", + "shield", + "back", + "headAccessory", + "eyewear", + "body", + } + + equipment = sum( + stats[attribute] + for gear in gear_set + if (equipped := user["items"]["gear"]["equipped"].get(gear)) + and (stats := content["gear"]["flat"].get(equipped)) + ) + + class_bonus = sum( + stats[attribute] / 2 + for gear in gear_set + if (equipped := user["items"]["gear"]["equipped"].get(gear)) + and (stats := content["gear"]["flat"].get(equipped)) + and stats["klass"] == user["stats"]["class"] + ) + + return { + "level": min(round(user["stats"]["lvl"] / 2), 50), + "equipment": equipment, + "class": class_bonus, + "allocated": user["stats"][attribute], + "buffs": user["stats"]["buffs"][attribute], + } + + +def get_attributes_total( + user: dict[str, Any], content: dict[str, Any], attribute: str +) -> int: + """Get total attribute points.""" + return floor( + sum(value for value in get_attribute_points(user, content, attribute).values()) + ) diff --git a/tests/components/habitica/conftest.py b/tests/components/habitica/conftest.py index b5ceadd2762..03b76561abc 100644 --- a/tests/components/habitica/conftest.py +++ b/tests/components/habitica/conftest.py @@ -56,6 +56,11 @@ def mock_habitica(aioclient_mock: AiohttpClientMocker) -> AiohttpClientMocker: f"{DEFAULT_URL}/api/v3/tasks/user", json=load_json_object_fixture("tasks.json", DOMAIN), ) + aioclient_mock.get( + f"{DEFAULT_URL}/api/v3/content", + params={"language": "en"}, + json=load_json_object_fixture("content.json", DOMAIN), + ) return aioclient_mock diff --git a/tests/components/habitica/fixtures/common_buttons_unavailable.json b/tests/components/habitica/fixtures/common_buttons_unavailable.json index 08039ae1762..efee5364e02 100644 --- a/tests/components/habitica/fixtures/common_buttons_unavailable.json +++ b/tests/components/habitica/fixtures/common_buttons_unavailable.json @@ -29,11 +29,26 @@ "preferences": { "sleep": false, "automaticAllocation": false, - "disableClasses": false + "disableClasses": false, + "language": "en" }, "flags": { "classSelected": true }, - "needsCron": false + "needsCron": false, + "items": { + "gear": { + "equipped": { + "weapon": "weapon_warrior_5", + "armor": "armor_warrior_5", + "head": "head_warrior_5", + "shield": "shield_warrior_5", + "back": "heroicAureole", + "headAccessory": "headAccessory_armoire_gogglesOfBookbinding", + "eyewear": "plagueDoctorMask", + "body": "aetherAmulet" + } + } + } } } diff --git a/tests/components/habitica/fixtures/content.json b/tests/components/habitica/fixtures/content.json new file mode 100644 index 00000000000..e8e14dead73 --- /dev/null +++ b/tests/components/habitica/fixtures/content.json @@ -0,0 +1,287 @@ +{ + "success": true, + "data": { + "gear": { + "flat": { + "weapon_warrior_5": { + "text": "Ruby Sword", + "notes": "Weapon whose forge-glow never fades. Increases Strength by 15. ", + "str": 15, + "value": 90, + "type": "weapon", + "key": "weapon_warrior_5", + "set": "warrior-5", + "klass": "warrior", + "index": "5", + "int": 0, + "per": 0, + "con": 0 + }, + "armor_warrior_5": { + "text": "Golden Armor", + "notes": "Looks ceremonial, but no known blade can pierce it. Increases Constitution by 11.", + "con": 11, + "value": 120, + "last": true, + "type": "armor", + "key": "armor_warrior_5", + "set": "warrior-5", + "klass": "warrior", + "index": "5", + "str": 0, + "int": 0, + "per": 0 + }, + "head_warrior_5": { + "text": "Golden Helm", + "notes": "Regal crown bound to shining armor. Increases Strength by 12.", + "str": 12, + "value": 80, + "last": true, + "type": "head", + "key": "head_warrior_5", + "set": "warrior-5", + "klass": "warrior", + "index": "5", + "int": 0, + "per": 0, + "con": 0 + }, + "shield_warrior_5": { + "text": "Golden Shield", + "notes": "Shining badge of the vanguard. Increases Constitution by 9.", + "con": 9, + "value": 90, + "last": true, + "type": "shield", + "key": "shield_warrior_5", + "set": "warrior-5", + "klass": "warrior", + "index": "5", + "str": 0, + "int": 0, + "per": 0 + }, + "weapon_wizard_5": { + "twoHanded": true, + "text": "Archmage Staff", + "notes": "Assists in weaving the most complex of spells. Increases Intelligence by 15 and Perception by 7. Two-handed item.", + "int": 15, + "per": 7, + "value": 160, + "type": "weapon", + "key": "weapon_wizard_5", + "set": "wizard-5", + "klass": "wizard", + "index": "5", + "str": 0, + "con": 0 + }, + "armor_wizard_5": { + "text": "Royal Magus Robe", + "notes": "Symbol of the power behind the throne. Increases Intelligence by 12.", + "int": 12, + "value": 120, + "last": true, + "type": "armor", + "key": "armor_wizard_5", + "set": "wizard-5", + "klass": "wizard", + "index": "5", + "str": 0, + "per": 0, + "con": 0 + }, + "head_wizard_5": { + "text": "Royal Magus Hat", + "notes": "Shows authority over fortune, weather, and lesser mages. Increases Perception by 10.", + "per": 10, + "value": 80, + "last": true, + "type": "head", + "key": "head_wizard_5", + "set": "wizard-5", + "klass": "wizard", + "index": "5", + "str": 0, + "int": 0, + "con": 0 + }, + "weapon_healer_5": { + "text": "Royal Scepter", + "notes": "Fit to grace the hand of a monarch, or of one who stands at a monarch's right hand. Increases Intelligence by 9. ", + "int": 9, + "value": 90, + "type": "weapon", + "key": "weapon_healer_5", + "set": "healer-5", + "klass": "healer", + "index": "5", + "str": 0, + "per": 0, + "con": 0 + }, + "armor_healer_5": { + "text": "Royal Mantle", + "notes": "Attire of those who have saved the lives of kings. Increases Constitution by 18.", + "con": 18, + "value": 120, + "last": true, + "type": "armor", + "key": "armor_healer_5", + "set": "healer-5", + "klass": "healer", + "index": "5", + "str": 0, + "int": 0, + "per": 0 + }, + "head_healer_5": { + "text": "Royal Diadem", + "notes": "For king, queen, or miracle-worker. Increases Intelligence by 9.", + "int": 9, + "value": 80, + "last": true, + "type": "head", + "key": "head_healer_5", + "set": "healer-5", + "klass": "healer", + "index": "5", + "str": 0, + "per": 0, + "con": 0 + }, + "shield_healer_5": { + "text": "Royal Shield", + "notes": "Bestowed upon those most dedicated to the kingdom's defense. Increases Constitution by 12.", + "con": 12, + "value": 90, + "last": true, + "type": "shield", + "key": "shield_healer_5", + "set": "healer-5", + "klass": "healer", + "index": "5", + "str": 0, + "int": 0, + "per": 0 + }, + "weapon_rogue_5": { + "text": "Ninja-to", + "notes": "Sleek and deadly as the ninja themselves. Increases Strength by 8. ", + "str": 8, + "value": 90, + "type": "weapon", + "key": "weapon_rogue_5", + "set": "rogue-5", + "klass": "rogue", + "index": "5", + "int": 0, + "per": 0, + "con": 0 + }, + "armor_rogue_5": { + "text": "Umbral Armor", + "notes": "Allows stealth in the open in broad daylight. Increases Perception by 18.", + "per": 18, + "value": 120, + "last": true, + "type": "armor", + "key": "armor_rogue_5", + "set": "rogue-5", + "klass": "rogue", + "index": "5", + "str": 0, + "int": 0, + "con": 0 + }, + "head_rogue_5": { + "text": "Umbral Hood", + "notes": "Conceals even thoughts from those who would probe them. Increases Perception by 12.", + "per": 12, + "value": 80, + "last": true, + "type": "head", + "key": "head_rogue_5", + "set": "rogue-5", + "klass": "rogue", + "index": "5", + "str": 0, + "int": 0, + "con": 0 + }, + "shield_rogue_5": { + "text": "Ninja-to", + "notes": "Sleek and deadly as the ninja themselves. Increases Strength by 8. ", + "str": 8, + "value": 90, + "type": "shield", + "key": "shield_rogue_5", + "set": "rogue-5", + "klass": "rogue", + "index": "5", + "int": 0, + "per": 0, + "con": 0 + }, + "back_special_heroicAureole": { + "text": "Heroic Aureole", + "notes": "The gems on this aureole glimmer when you tell your tales of glory. Increases all stats by 7.", + "con": 7, + "str": 7, + "per": 7, + "int": 7, + "value": 175, + "type": "back", + "key": "back_special_heroicAureole", + "set": "special-heroicAureole", + "klass": "special", + "index": "heroicAureole" + }, + "headAccessory_armoire_gogglesOfBookbinding": { + "per": 8, + "set": "bookbinder", + "notes": "These goggles will help you zero in on any task, large or small! Increases Perception by 8. Enchanted Armoire: Bookbinder Set (Item 1 of 4).", + "text": "Goggles of Bookbinding", + "value": 100, + "type": "headAccessory", + "key": "headAccessory_armoire_gogglesOfBookbinding", + "klass": "armoire", + "index": "gogglesOfBookbinding", + "str": 0, + "int": 0, + "con": 0 + }, + "eyewear_armoire_plagueDoctorMask": { + "con": 5, + "int": 5, + "set": "plagueDoctor", + "notes": "An authentic mask worn by the doctors who battle the Plague of Procrastination. Increases Constitution and Intelligence by 5 each. Enchanted Armoire: Plague Doctor Set (Item 2 of 3).", + "text": "Plague Doctor Mask", + "value": 100, + "type": "eyewear", + "key": "eyewear_armoire_plagueDoctorMask", + "klass": "armoire", + "index": "plagueDoctorMask", + "str": 0, + "per": 0 + }, + "body_special_aetherAmulet": { + "text": "Aether Amulet", + "notes": "This amulet has a mysterious history. Increases Constitution and Strength by 10 each.", + "value": 175, + "str": 10, + "con": 10, + "type": "body", + "key": "body_special_aetherAmulet", + "set": "special-aetherAmulet", + "klass": "special", + "index": "aetherAmulet", + "int": 0, + "per": 0 + } + } + } + }, + "appVersion": "5.29.2" +} diff --git a/tests/components/habitica/fixtures/healer_fixture.json b/tests/components/habitica/fixtures/healer_fixture.json index 04cbabcfa2d..85f719f4ca7 100644 --- a/tests/components/habitica/fixtures/healer_fixture.json +++ b/tests/components/habitica/fixtures/healer_fixture.json @@ -4,10 +4,10 @@ "profile": { "name": "test-user" }, "stats": { "buffs": { - "str": 0, - "int": 0, - "per": 0, - "con": 0, + "str": 26, + "int": 26, + "per": 26, + "con": 26, "stealth": 0, "streaks": false, "seafoam": false, @@ -24,17 +24,36 @@ "maxHealth": 50, "maxMP": 166, "toNextLevel": 880, - "points": 5 + "points": 5, + "str": 15, + "con": 15, + "int": 15, + "per": 15 }, "preferences": { "sleep": false, "automaticAllocation": true, - "disableClasses": false + "disableClasses": false, + "language": "en" }, "flags": { "classSelected": true }, "needsCron": true, - "lastCron": "2024-09-21T22:01:55.586Z" + "lastCron": "2024-09-21T22:01:55.586Z", + "items": { + "gear": { + "equipped": { + "weapon": "weapon_healer_5", + "armor": "armor_healer_5", + "head": "head_healer_5", + "shield": "shield_healer_5", + "back": "heroicAureole", + "headAccessory": "headAccessory_armoire_gogglesOfBookbinding", + "eyewear": "plagueDoctorMask", + "body": "aetherAmulet" + } + } + } } } diff --git a/tests/components/habitica/fixtures/healer_skills_unavailable.json b/tests/components/habitica/fixtures/healer_skills_unavailable.json index 305a5f8cda1..a6bff246b2a 100644 --- a/tests/components/habitica/fixtures/healer_skills_unavailable.json +++ b/tests/components/habitica/fixtures/healer_skills_unavailable.json @@ -4,10 +4,10 @@ "profile": { "name": "test-user" }, "stats": { "buffs": { - "str": 0, - "int": 0, - "per": 0, - "con": 0, + "str": 26, + "int": 26, + "per": 26, + "con": 26, "stealth": 0, "streaks": false, "seafoam": false, @@ -24,16 +24,35 @@ "maxHealth": 50, "maxMP": 166, "toNextLevel": 880, - "points": 0 + "points": 0, + "str": 15, + "con": 15, + "int": 15, + "per": 15 }, "preferences": { "sleep": false, "automaticAllocation": false, - "disableClasses": false + "disableClasses": false, + "language": "en" }, "flags": { "classSelected": true }, - "needsCron": false + "needsCron": false, + "items": { + "gear": { + "equipped": { + "weapon": "weapon_healer_5", + "armor": "armor_healer_5", + "head": "head_healer_5", + "shield": "shield_healer_5", + "back": "heroicAureole", + "headAccessory": "headAccessory_armoire_gogglesOfBookbinding", + "eyewear": "plagueDoctorMask", + "body": "aetherAmulet" + } + } + } } } diff --git a/tests/components/habitica/fixtures/quest_invitation_off.json b/tests/components/habitica/fixtures/quest_invitation_off.json index f862a85c7c4..b5eccd99e10 100644 --- a/tests/components/habitica/fixtures/quest_invitation_off.json +++ b/tests/components/habitica/fixtures/quest_invitation_off.json @@ -29,7 +29,8 @@ "preferences": { "sleep": false, "automaticAllocation": true, - "disableClasses": false + "disableClasses": false, + "language": "en" }, "flags": { "classSelected": true diff --git a/tests/components/habitica/fixtures/rogue_fixture.json b/tests/components/habitica/fixtures/rogue_fixture.json index f0ea42a7182..1e5e996c034 100644 --- a/tests/components/habitica/fixtures/rogue_fixture.json +++ b/tests/components/habitica/fixtures/rogue_fixture.json @@ -4,10 +4,10 @@ "profile": { "name": "test-user" }, "stats": { "buffs": { - "str": 0, - "int": 0, - "per": 0, - "con": 0, + "str": 26, + "int": 26, + "per": 26, + "con": 26, "stealth": 0, "streaks": false, "seafoam": false, @@ -24,17 +24,36 @@ "maxHealth": 50, "maxMP": 166, "toNextLevel": 880, - "points": 5 + "points": 5, + "str": 15, + "con": 15, + "int": 15, + "per": 15 }, "preferences": { "sleep": false, "automaticAllocation": true, - "disableClasses": false + "disableClasses": false, + "language": "en" }, "flags": { "classSelected": true }, "needsCron": true, - "lastCron": "2024-09-21T22:01:55.586Z" + "lastCron": "2024-09-21T22:01:55.586Z", + "items": { + "gear": { + "equipped": { + "weapon": "weapon_rogue_5", + "armor": "armor_rogue_5", + "head": "head_rogue_5", + "shield": "shield_rogue_5", + "back": "heroicAureole", + "headAccessory": "headAccessory_armoire_gogglesOfBookbinding", + "eyewear": "plagueDoctorMask", + "body": "aetherAmulet" + } + } + } } } diff --git a/tests/components/habitica/fixtures/rogue_skills_unavailable.json b/tests/components/habitica/fixtures/rogue_skills_unavailable.json index 2709731ba55..c7c5ff32245 100644 --- a/tests/components/habitica/fixtures/rogue_skills_unavailable.json +++ b/tests/components/habitica/fixtures/rogue_skills_unavailable.json @@ -4,10 +4,10 @@ "profile": { "name": "test-user" }, "stats": { "buffs": { - "str": 0, - "int": 0, - "per": 0, - "con": 0, + "str": 26, + "int": 26, + "per": 26, + "con": 26, "stealth": 0, "streaks": true, "seafoam": false, @@ -24,16 +24,35 @@ "maxHealth": 50, "maxMP": 166, "toNextLevel": 880, - "points": 0 + "points": 0, + "str": 15, + "con": 15, + "int": 15, + "per": 15 }, "preferences": { "sleep": false, "automaticAllocation": false, - "disableClasses": false + "disableClasses": false, + "language": "en" }, "flags": { "classSelected": true }, - "needsCron": false + "needsCron": false, + "items": { + "gear": { + "equipped": { + "weapon": "weapon_rogue_5", + "armor": "armor_rogue_5", + "head": "head_rogue_5", + "shield": "shield_rogue_5", + "back": "heroicAureole", + "headAccessory": "headAccessory_armoire_gogglesOfBookbinding", + "eyewear": "plagueDoctorMask", + "body": "aetherAmulet" + } + } + } } } diff --git a/tests/components/habitica/fixtures/rogue_stealth_unavailable.json b/tests/components/habitica/fixtures/rogue_stealth_unavailable.json index a4e86abbb91..9fd7adcca42 100644 --- a/tests/components/habitica/fixtures/rogue_stealth_unavailable.json +++ b/tests/components/habitica/fixtures/rogue_stealth_unavailable.json @@ -4,10 +4,10 @@ "profile": { "name": "test-user" }, "stats": { "buffs": { - "str": 0, - "int": 0, - "per": 0, - "con": 0, + "str": 26, + "int": 26, + "per": 26, + "con": 26, "stealth": 4, "streaks": false, "seafoam": false, @@ -24,16 +24,35 @@ "maxHealth": 50, "maxMP": 166, "toNextLevel": 880, - "points": 0 + "points": 0, + "str": 15, + "con": 15, + "int": 15, + "per": 15 }, "preferences": { "sleep": false, "automaticAllocation": false, - "disableClasses": false + "disableClasses": false, + "language": "en" }, "flags": { "classSelected": true }, - "needsCron": false + "needsCron": false, + "items": { + "gear": { + "equipped": { + "weapon": "weapon_rogue_5", + "armor": "armor_rogue_5", + "head": "head_rogue_5", + "shield": "shield_rogue_5", + "back": "heroicAureole", + "headAccessory": "headAccessory_armoire_gogglesOfBookbinding", + "eyewear": "plagueDoctorMask", + "body": "aetherAmulet" + } + } + } } } diff --git a/tests/components/habitica/fixtures/user.json b/tests/components/habitica/fixtures/user.json index 818f4ed4eda..569c5b81a02 100644 --- a/tests/components/habitica/fixtures/user.json +++ b/tests/components/habitica/fixtures/user.json @@ -4,10 +4,10 @@ "profile": { "name": "test-user" }, "stats": { "buffs": { - "str": 0, - "int": 0, - "per": 0, - "con": 0, + "str": 26, + "int": 26, + "per": 26, + "con": 26, "stealth": 0, "streaks": false, "seafoam": false, @@ -24,12 +24,17 @@ "maxHealth": 50, "maxMP": 166, "toNextLevel": 880, - "points": 5 + "points": 5, + "str": 15, + "con": 15, + "int": 15, + "per": 15 }, "preferences": { "sleep": false, "automaticAllocation": true, - "disableClasses": false + "disableClasses": false, + "language": "en" }, "flags": { "classSelected": true @@ -59,6 +64,20 @@ } }, "needsCron": true, - "lastCron": "2024-09-21T22:01:55.586Z" + "lastCron": "2024-09-21T22:01:55.586Z", + "items": { + "gear": { + "equipped": { + "weapon": "weapon_warrior_5", + "armor": "armor_warrior_5", + "head": "head_warrior_5", + "shield": "shield_warrior_5", + "back": "heroicAureole", + "headAccessory": "headAccessory_armoire_gogglesOfBookbinding", + "eyewear": "plagueDoctorMask", + "body": "aetherAmulet" + } + } + } } } diff --git a/tests/components/habitica/fixtures/warrior_fixture.json b/tests/components/habitica/fixtures/warrior_fixture.json index 53d18206f9a..3517e8a908a 100644 --- a/tests/components/habitica/fixtures/warrior_fixture.json +++ b/tests/components/habitica/fixtures/warrior_fixture.json @@ -4,10 +4,10 @@ "profile": { "name": "test-user" }, "stats": { "buffs": { - "str": 0, - "int": 0, - "per": 0, - "con": 0, + "str": 26, + "int": 26, + "per": 26, + "con": 26, "stealth": 0, "streaks": false, "seafoam": false, @@ -24,17 +24,36 @@ "maxHealth": 50, "maxMP": 166, "toNextLevel": 880, - "points": 5 + "points": 5, + "str": 15, + "con": 15, + "int": 15, + "per": 15 }, "preferences": { "sleep": false, "automaticAllocation": true, - "disableClasses": false + "disableClasses": false, + "language": "en" }, "flags": { "classSelected": true }, "needsCron": true, - "lastCron": "2024-09-21T22:01:55.586Z" + "lastCron": "2024-09-21T22:01:55.586Z", + "items": { + "gear": { + "equipped": { + "weapon": "weapon_warrior_5", + "armor": "armor_warrior_5", + "head": "head_warrior_5", + "shield": "shield_warrior_5", + "back": "heroicAureole", + "headAccessory": "headAccessory_armoire_gogglesOfBookbinding", + "eyewear": "plagueDoctorMask", + "body": "aetherAmulet" + } + } + } } } diff --git a/tests/components/habitica/fixtures/warrior_skills_unavailable.json b/tests/components/habitica/fixtures/warrior_skills_unavailable.json index 53160646569..b3d33c85d5c 100644 --- a/tests/components/habitica/fixtures/warrior_skills_unavailable.json +++ b/tests/components/habitica/fixtures/warrior_skills_unavailable.json @@ -4,10 +4,10 @@ "profile": { "name": "test-user" }, "stats": { "buffs": { - "str": 0, - "int": 0, - "per": 0, - "con": 0, + "str": 26, + "int": 26, + "per": 26, + "con": 26, "stealth": 0, "streaks": false, "seafoam": false, @@ -24,16 +24,35 @@ "maxHealth": 50, "maxMP": 166, "toNextLevel": 880, - "points": 0 + "points": 0, + "str": 15, + "con": 15, + "int": 15, + "per": 15 }, "preferences": { "sleep": false, "automaticAllocation": false, - "disableClasses": false + "disableClasses": false, + "language": "en" }, "flags": { "classSelected": true }, - "needsCron": false + "needsCron": false, + "items": { + "gear": { + "equipped": { + "weapon": "weapon_warrior_5", + "armor": "armor_warrior_5", + "head": "head_warrior_5", + "shield": "shield_warrior_5", + "back": "heroicAureole", + "headAccessory": "headAccessory_armoire_gogglesOfBookbinding", + "eyewear": "plagueDoctorMask", + "body": "aetherAmulet" + } + } + } } } diff --git a/tests/components/habitica/fixtures/wizard_fixture.json b/tests/components/habitica/fixtures/wizard_fixture.json index 0f9f2a49639..de596e231de 100644 --- a/tests/components/habitica/fixtures/wizard_fixture.json +++ b/tests/components/habitica/fixtures/wizard_fixture.json @@ -4,10 +4,10 @@ "profile": { "name": "test-user" }, "stats": { "buffs": { - "str": 0, - "int": 0, - "per": 0, - "con": 0, + "str": 26, + "int": 26, + "per": 26, + "con": 26, "stealth": 0, "streaks": false, "seafoam": false, @@ -24,17 +24,36 @@ "maxHealth": 50, "maxMP": 166, "toNextLevel": 880, - "points": 5 + "points": 5, + "str": 15, + "con": 15, + "int": 15, + "per": 15 }, "preferences": { "sleep": false, "automaticAllocation": true, - "disableClasses": false + "disableClasses": false, + "language": "en" }, "flags": { "classSelected": true }, "needsCron": true, - "lastCron": "2024-09-21T22:01:55.586Z" + "lastCron": "2024-09-21T22:01:55.586Z", + "items": { + "gear": { + "equipped": { + "weapon": "weapon_wizard_5", + "armor": "armor_wizard_5", + "head": "head_wizard_5", + "shield": "shield_base_0", + "back": "heroicAureole", + "headAccessory": "headAccessory_armoire_gogglesOfBookbinding", + "eyewear": "plagueDoctorMask", + "body": "aetherAmulet" + } + } + } } } diff --git a/tests/components/habitica/fixtures/wizard_frost_unavailable.json b/tests/components/habitica/fixtures/wizard_frost_unavailable.json index ba57568e99e..31d10fde4b9 100644 --- a/tests/components/habitica/fixtures/wizard_frost_unavailable.json +++ b/tests/components/habitica/fixtures/wizard_frost_unavailable.json @@ -4,10 +4,10 @@ "profile": { "name": "test-user" }, "stats": { "buffs": { - "str": 0, - "int": 0, - "per": 0, - "con": 0, + "str": 26, + "int": 26, + "per": 26, + "con": 26, "stealth": 0, "streaks": true, "seafoam": false, @@ -24,16 +24,35 @@ "maxHealth": 50, "maxMP": 166, "toNextLevel": 880, - "points": 0 + "points": 0, + "str": 15, + "con": 15, + "int": 15, + "per": 15 }, "preferences": { "sleep": false, "automaticAllocation": false, - "disableClasses": false + "disableClasses": false, + "language": "en" }, "flags": { "classSelected": true }, - "needsCron": false + "needsCron": false, + "items": { + "gear": { + "equipped": { + "weapon": "weapon_wizard_5", + "armor": "armor_wizard_5", + "head": "head_wizard_5", + "shield": "shield_base_0", + "back": "heroicAureole", + "headAccessory": "headAccessory_armoire_gogglesOfBookbinding", + "eyewear": "plagueDoctorMask", + "body": "aetherAmulet" + } + } + } } } diff --git a/tests/components/habitica/fixtures/wizard_skills_unavailable.json b/tests/components/habitica/fixtures/wizard_skills_unavailable.json index 11bf0a19193..f3bdee9dd74 100644 --- a/tests/components/habitica/fixtures/wizard_skills_unavailable.json +++ b/tests/components/habitica/fixtures/wizard_skills_unavailable.json @@ -4,10 +4,10 @@ "profile": { "name": "test-user" }, "stats": { "buffs": { - "str": 0, - "int": 0, - "per": 0, - "con": 0, + "str": 26, + "int": 26, + "per": 26, + "con": 26, "stealth": 0, "streaks": false, "seafoam": false, @@ -24,16 +24,35 @@ "maxHealth": 50, "maxMP": 166, "toNextLevel": 880, - "points": 0 + "points": 0, + "str": 15, + "con": 15, + "int": 15, + "per": 15 }, "preferences": { "sleep": false, "automaticAllocation": false, - "disableClasses": false + "disableClasses": false, + "language": "en" }, "flags": { "classSelected": true }, - "needsCron": false + "needsCron": false, + "items": { + "gear": { + "equipped": { + "weapon": "weapon_wizard_5", + "armor": "armor_wizard_5", + "head": "head_wizard_5", + "shield": "shield_base_0", + "back": "heroicAureole", + "headAccessory": "headAccessory_armoire_gogglesOfBookbinding", + "eyewear": "plagueDoctorMask", + "body": "aetherAmulet" + } + } + } } } diff --git a/tests/components/habitica/snapshots/test_sensor.ambr b/tests/components/habitica/snapshots/test_sensor.ambr index ee75b424a93..3a43069bfc4 100644 --- a/tests/components/habitica/snapshots/test_sensor.ambr +++ b/tests/components/habitica/snapshots/test_sensor.ambr @@ -59,6 +59,61 @@ 'state': 'wizard', }) # --- +# name: test_sensors[sensor.test_user_constitution-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.test_user_constitution', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Constitution', + 'platform': 'habitica', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '00000000-0000-0000-0000-000000000000_constitution', + 'unit_of_measurement': 'CON', + }) +# --- +# name: test_sensors[sensor.test_user_constitution-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'allocated': 15, + 'buffs': 26, + 'class': 0, + 'equipment': 20, + 'friendly_name': 'test-user Constitution', + 'level': 19, + 'unit_of_measurement': 'CON', + }), + 'context': , + 'entity_id': 'sensor.test_user_constitution', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '80', + }) +# --- # name: test_sensors[sensor.test_user_dailies-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -567,6 +622,61 @@ 'state': '0', }) # --- +# name: test_sensors[sensor.test_user_intelligence-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.test_user_intelligence', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Intelligence', + 'platform': 'habitica', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '00000000-0000-0000-0000-000000000000_intelligence', + 'unit_of_measurement': 'INT', + }) +# --- +# name: test_sensors[sensor.test_user_intelligence-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'allocated': 15, + 'buffs': 26, + 'class': 0, + 'equipment': 0, + 'friendly_name': 'test-user Intelligence', + 'level': 19, + 'unit_of_measurement': 'INT', + }), + 'context': , + 'entity_id': 'sensor.test_user_intelligence', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '60', + }) +# --- # name: test_sensors[sensor.test_user_level-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -854,6 +964,61 @@ 'state': '880', }) # --- +# name: test_sensors[sensor.test_user_perception-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.test_user_perception', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Perception', + 'platform': 'habitica', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '00000000-0000-0000-0000-000000000000_perception', + 'unit_of_measurement': 'PER', + }) +# --- +# name: test_sensors[sensor.test_user_perception-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'allocated': 15, + 'buffs': 26, + 'class': 0, + 'equipment': 8, + 'friendly_name': 'test-user Perception', + 'level': 19, + 'unit_of_measurement': 'PER', + }), + 'context': , + 'entity_id': 'sensor.test_user_perception', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '68', + }) +# --- # name: test_sensors[sensor.test_user_rewards-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -915,6 +1080,61 @@ 'state': '1', }) # --- +# name: test_sensors[sensor.test_user_strength-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.test_user_strength', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Strength', + 'platform': 'habitica', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '00000000-0000-0000-0000-000000000000_strength', + 'unit_of_measurement': 'STR', + }) +# --- +# name: test_sensors[sensor.test_user_strength-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'allocated': 15, + 'buffs': 26, + 'class': 0, + 'equipment': 27, + 'friendly_name': 'test-user Strength', + 'level': 19, + 'unit_of_measurement': 'STR', + }), + 'context': , + 'entity_id': 'sensor.test_user_strength', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '87', + }) +# --- # name: test_sensors[sensor.test_user_to_do_s-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/habitica/test_binary_sensor.py b/tests/components/habitica/test_binary_sensor.py index 5b19cd008bf..1710f8f217e 100644 --- a/tests/components/habitica/test_binary_sensor.py +++ b/tests/components/habitica/test_binary_sensor.py @@ -66,7 +66,11 @@ async def test_pending_quest_states( json=load_json_object_fixture(f"{fixture}.json", DOMAIN), ) aioclient_mock.get(f"{DEFAULT_URL}/api/v3/tasks/user", json={"data": []}) - + aioclient_mock.get( + f"{DEFAULT_URL}/api/v3/content", + params={"language": "en"}, + json=load_json_object_fixture("content.json", DOMAIN), + ) config_entry.add_to_hass(hass) await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() diff --git a/tests/components/habitica/test_button.py b/tests/components/habitica/test_button.py index 6bd62f3a58e..979cefef923 100644 --- a/tests/components/habitica/test_button.py +++ b/tests/components/habitica/test_button.py @@ -63,6 +63,11 @@ async def test_buttons( f"{DEFAULT_URL}/api/v3/tasks/user", json=load_json_object_fixture("tasks.json", DOMAIN), ) + aioclient_mock.get( + f"{DEFAULT_URL}/api/v3/content", + params={"language": "en"}, + json=load_json_object_fixture("content.json", DOMAIN), + ) config_entry.add_to_hass(hass) await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() @@ -163,6 +168,11 @@ async def test_button_press( f"{DEFAULT_URL}/api/v3/tasks/user", json=load_json_object_fixture("tasks.json", DOMAIN), ) + aioclient_mock.get( + f"{DEFAULT_URL}/api/v3/content", + params={"language": "en"}, + json=load_json_object_fixture("content.json", DOMAIN), + ) config_entry.add_to_hass(hass) await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() diff --git a/tests/components/habitica/test_todo.py b/tests/components/habitica/test_todo.py index 88947caba2d..c9a4b3dd37a 100644 --- a/tests/components/habitica/test_todo.py +++ b/tests/components/habitica/test_todo.py @@ -672,6 +672,11 @@ async def test_next_due_date( f"{DEFAULT_URL}/api/v3/tasks/user", json=load_json_object_fixture(fixture, DOMAIN), ) + aioclient_mock.get( + f"{DEFAULT_URL}/api/v3/content", + params={"language": "en"}, + json=load_json_object_fixture("content.json", DOMAIN), + ) config_entry.add_to_hass(hass) await hass.config_entries.async_setup(config_entry.entry_id)