mirror of
https://github.com/esphome/esphome.git
synced 2026-09-01 10:36:01 +00:00
Add integration test for deprecated FanTraits compat layer
This commit is contained in:
@@ -0,0 +1 @@
|
||||
"""Legacy fan component — tests deprecated FanTraits setters backward compat."""
|
||||
@@ -0,0 +1,19 @@
|
||||
"""Legacy fan platform that uses deprecated FanTraits setters."""
|
||||
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import fan
|
||||
import esphome.config_validation as cv
|
||||
|
||||
legacy_fan_ns = cg.esphome_ns.namespace("legacy_fan_test")
|
||||
LegacyFan = legacy_fan_ns.class_("LegacyFan", fan.Fan, cg.Component)
|
||||
|
||||
CONFIG_SCHEMA = fan.FAN_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(LegacyFan),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = await fan.new_fan(config)
|
||||
await cg.register_component(var, config)
|
||||
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/components/fan/fan.h"
|
||||
#include "esphome/core/component.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace legacy_fan_test {
|
||||
|
||||
/// Test fan that uses the DEPRECATED FanTraits setters for preset modes.
|
||||
/// This validates backward compatibility for external components that haven't migrated.
|
||||
class LegacyFan : public fan::Fan, public Component {
|
||||
public:
|
||||
void setup() override {
|
||||
auto restore = this->restore_state_();
|
||||
if (restore.has_value()) {
|
||||
restore->apply(*this);
|
||||
}
|
||||
this->publish_state();
|
||||
}
|
||||
|
||||
float get_setup_priority() const override { return setup_priority::LATE; }
|
||||
|
||||
fan::FanTraits get_traits() override {
|
||||
auto traits = fan::FanTraits(false, true, false, 3);
|
||||
|
||||
// DEPRECATED API: setting preset modes directly on FanTraits.
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
traits.set_supported_preset_modes({"Turbo", "Silent", "Eco"});
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
return traits;
|
||||
}
|
||||
|
||||
protected:
|
||||
void control(const fan::FanCall &call) override {
|
||||
if (call.get_state().has_value()) {
|
||||
this->state = *call.get_state();
|
||||
}
|
||||
if (call.get_speed().has_value()) {
|
||||
this->speed = *call.get_speed();
|
||||
}
|
||||
this->apply_preset_mode_(call);
|
||||
this->publish_state();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace legacy_fan_test
|
||||
} // namespace esphome
|
||||
@@ -0,0 +1,21 @@
|
||||
esphome:
|
||||
name: legacy-fan-compat
|
||||
platformio_options:
|
||||
build_flags:
|
||||
- "-DUSE_HOST"
|
||||
|
||||
host:
|
||||
api:
|
||||
logger:
|
||||
level: DEBUG
|
||||
|
||||
external_components:
|
||||
- source:
|
||||
type: local
|
||||
path: EXTERNAL_COMPONENT_PATH
|
||||
components: [legacy_fan_component]
|
||||
|
||||
fan:
|
||||
- platform: legacy_fan_component
|
||||
name: "Legacy Fan"
|
||||
id: legacy_fan
|
||||
@@ -0,0 +1,79 @@
|
||||
"""Integration test for backward compatibility of deprecated FanTraits setters.
|
||||
|
||||
Verifies that external components using the old traits.set_supported_preset_modes()
|
||||
API still work correctly during the deprecation period (removed in 2026.11.0).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
|
||||
from aioesphomeapi import FanInfo, FanState
|
||||
import pytest
|
||||
|
||||
from .types import APIClientConnectedFactory, RunCompiledFunction
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_legacy_fan_compat(
|
||||
yaml_config: str,
|
||||
run_compiled: RunCompiledFunction,
|
||||
api_client_connected: APIClientConnectedFactory,
|
||||
) -> None:
|
||||
"""Test that deprecated FanTraits preset mode setters still work end-to-end."""
|
||||
external_components_path = str(
|
||||
Path(__file__).parent / "fixtures" / "external_components"
|
||||
)
|
||||
yaml_config = yaml_config.replace(
|
||||
"EXTERNAL_COMPONENT_PATH", external_components_path
|
||||
)
|
||||
|
||||
async with run_compiled(yaml_config), api_client_connected() as client:
|
||||
entities, services = await client.list_entities_services()
|
||||
|
||||
fan_infos = [e for e in entities if isinstance(e, FanInfo)]
|
||||
assert len(fan_infos) == 1, f"Expected 1 fan entity, got {len(fan_infos)}"
|
||||
|
||||
test_fan = fan_infos[0]
|
||||
|
||||
# Verify preset modes set via deprecated FanTraits setter are exposed
|
||||
assert set(test_fan.supported_preset_modes) == {
|
||||
"Turbo",
|
||||
"Silent",
|
||||
"Eco",
|
||||
}, (
|
||||
f"Expected preset modes {{Turbo, Silent, Eco}}, "
|
||||
f"got {test_fan.supported_preset_modes}"
|
||||
)
|
||||
|
||||
# Verify speed support
|
||||
assert test_fan.supports_speed is True
|
||||
assert test_fan.supported_speed_count == 3
|
||||
|
||||
# Subscribe and wait for initial states
|
||||
states: dict[int, FanState] = {}
|
||||
state_event = asyncio.Event()
|
||||
|
||||
def on_state(state: FanState) -> None:
|
||||
if isinstance(state, FanState):
|
||||
states[state.key] = state
|
||||
state_event.set()
|
||||
|
||||
client.subscribe_states(on_state)
|
||||
|
||||
# Wait for initial state
|
||||
await asyncio.wait_for(state_event.wait(), timeout=5.0)
|
||||
|
||||
# Turn on fan with preset mode (tests find_preset_mode_ compat path)
|
||||
state_event.clear()
|
||||
client.fan_command(
|
||||
key=test_fan.key,
|
||||
state=True,
|
||||
preset_mode="Turbo",
|
||||
)
|
||||
await asyncio.wait_for(state_event.wait(), timeout=5.0)
|
||||
|
||||
fan_state = states[test_fan.key]
|
||||
assert fan_state.state is True
|
||||
assert fan_state.preset_mode == "Turbo"
|
||||
Reference in New Issue
Block a user