1
0
mirror of https://github.com/home-assistant/core.git synced 2026-05-27 10:46:38 +01:00

Improve Israel Rail departure sensor coverage (#171397)

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Miko Stern
2026-05-27 00:09:39 +03:00
committed by GitHub
parent 06c92cd328
commit ffcab49087
5 changed files with 629 additions and 41 deletions
@@ -79,6 +79,17 @@ class IsraelRailDataUpdateCoordinator(DataUpdateCoordinator[list[DataConnection]
"Unable to connect and retrieve data from israelrail api",
) from e
offset = 0
now = dt_util.now()
while offset < len(train_routes):
route = train_routes[offset]
if route is None:
break
route_departure = departure_time(route)
if route_departure is None or route_departure >= now:
break
offset += 1
return [
DataConnection(
departure=departure_time(train_routes[i]),
@@ -89,6 +100,6 @@ class IsraelRailDataUpdateCoordinator(DataUpdateCoordinator[list[DataConnection]
start=station_name_to_id(train_routes[i].trains[0].src),
destination=station_name_to_id(train_routes[i].trains[-1].dst),
)
for i in range(DEPARTURES_COUNT)
for i in range(offset, offset + DEPARTURES_COUNT)
if len(train_routes) > i and train_routes[i] is not None
]
+40 -24
View File
@@ -52,30 +52,46 @@ DEPARTURE_SENSORS: tuple[IsraelRailSensorEntityDescription, ...] = (
)
SENSORS: tuple[IsraelRailSensorEntityDescription, ...] = (
IsraelRailSensorEntityDescription(
key="platform",
translation_key="platform",
value_fn=lambda data_connection: data_connection.platform,
),
IsraelRailSensorEntityDescription(
key="trains",
translation_key="trains",
value_fn=lambda data_connection: data_connection.trains,
),
IsraelRailSensorEntityDescription(
key="train_number",
translation_key="train_number",
value_fn=lambda data_connection: data_connection.train_number,
),
IsraelRailSensorEntityDescription(
key="departure_delay",
translation_key="departure_delay",
device_class=SensorDeviceClass.DURATION,
native_unit_of_measurement=UnitOfTime.MINUTES,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=0,
value_fn=lambda data_connection: data_connection.departure_delay,
),
*[
IsraelRailSensorEntityDescription(
key=f"platform{i or ''}",
translation_key=f"platform{i or ''}",
value_fn=lambda data_connection: data_connection.platform,
index=i,
)
for i in range(DEPARTURES_COUNT)
],
*[
IsraelRailSensorEntityDescription(
key=f"trains{i or ''}",
translation_key=f"trains{i or ''}",
value_fn=lambda data_connection: data_connection.trains,
index=i,
)
for i in range(DEPARTURES_COUNT)
],
*[
IsraelRailSensorEntityDescription(
key=f"train_number{i or ''}",
translation_key=f"train_number{i or ''}",
value_fn=lambda data_connection: data_connection.train_number,
index=i,
)
for i in range(DEPARTURES_COUNT)
],
*[
IsraelRailSensorEntityDescription(
key=f"departure_delay{i or ''}",
translation_key=f"departure_delay{i or ''}",
device_class=SensorDeviceClass.DURATION,
native_unit_of_measurement=UnitOfTime.MINUTES,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=0,
value_fn=lambda data_connection: data_connection.departure_delay,
index=i,
)
for i in range(DEPARTURES_COUNT)
],
)
@@ -31,14 +31,38 @@
"departure_delay": {
"name": "Departure delay"
},
"departure_delay1": {
"name": "Departure delay +1"
},
"departure_delay2": {
"name": "Departure delay +2"
},
"platform": {
"name": "Platform"
},
"platform1": {
"name": "Platform +1"
},
"platform2": {
"name": "Platform +2"
},
"train_number": {
"name": "Train number"
},
"train_number1": {
"name": "Train number +1"
},
"train_number2": {
"name": "Train number +2"
},
"trains": {
"name": "Trains"
},
"trains1": {
"name": "Trains +1"
},
"trains2": {
"name": "Trains +2"
}
}
}
@@ -214,6 +214,124 @@
'state': '0',
})
# ---
# name: test_valid_config[sensor.mock_title_departure_delay_1-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_departure_delay_1',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Departure delay +1',
'options': dict({
'sensor': dict({
'suggested_display_precision': 0,
}),
}),
'original_device_class': <SensorDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'Departure delay +1',
'platform': 'israel_rail',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'departure_delay1',
'unique_id': 'באר יעקב אשקלון_departure_delay1',
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
})
# ---
# name: test_valid_config[sensor.mock_title_departure_delay_1-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by Israel rail.',
'device_class': 'duration',
'friendly_name': 'Mock Title Departure delay +1',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_departure_delay_1',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0',
})
# ---
# name: test_valid_config[sensor.mock_title_departure_delay_2-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_departure_delay_2',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Departure delay +2',
'options': dict({
'sensor': dict({
'suggested_display_precision': 0,
}),
}),
'original_device_class': <SensorDeviceClass.DURATION: 'duration'>,
'original_icon': None,
'original_name': 'Departure delay +2',
'platform': 'israel_rail',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'departure_delay2',
'unique_id': 'באר יעקב אשקלון_departure_delay2',
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
})
# ---
# name: test_valid_config[sensor.mock_title_departure_delay_2-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by Israel rail.',
'device_class': 'duration',
'friendly_name': 'Mock Title Departure delay +2',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_departure_delay_2',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '0',
})
# ---
# name: test_valid_config[sensor.mock_title_platform-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
@@ -265,6 +383,108 @@
'state': '1',
})
# ---
# name: test_valid_config[sensor.mock_title_platform_1-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_platform_1',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Platform +1',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Platform +1',
'platform': 'israel_rail',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'platform1',
'unique_id': 'באר יעקב אשקלון_platform1',
'unit_of_measurement': None,
})
# ---
# name: test_valid_config[sensor.mock_title_platform_1-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by Israel rail.',
'friendly_name': 'Mock Title Platform +1',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_platform_1',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '1',
})
# ---
# name: test_valid_config[sensor.mock_title_platform_2-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_platform_2',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Platform +2',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Platform +2',
'platform': 'israel_rail',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'platform2',
'unique_id': 'באר יעקב אשקלון_platform2',
'unit_of_measurement': None,
})
# ---
# name: test_valid_config[sensor.mock_title_platform_2-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by Israel rail.',
'friendly_name': 'Mock Title Platform +2',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_platform_2',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '1',
})
# ---
# name: test_valid_config[sensor.mock_title_train_number-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
@@ -316,6 +536,108 @@
'state': '1234',
})
# ---
# name: test_valid_config[sensor.mock_title_train_number_1-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_train_number_1',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Train number +1',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Train number +1',
'platform': 'israel_rail',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'train_number1',
'unique_id': 'באר יעקב אשקלון_train_number1',
'unit_of_measurement': None,
})
# ---
# name: test_valid_config[sensor.mock_title_train_number_1-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by Israel rail.',
'friendly_name': 'Mock Title Train number +1',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_train_number_1',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '1235',
})
# ---
# name: test_valid_config[sensor.mock_title_train_number_2-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_train_number_2',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Train number +2',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Train number +2',
'platform': 'israel_rail',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'train_number2',
'unique_id': 'באר יעקב אשקלון_train_number2',
'unit_of_measurement': None,
})
# ---
# name: test_valid_config[sensor.mock_title_train_number_2-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by Israel rail.',
'friendly_name': 'Mock Title Train number +2',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_train_number_2',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '1236',
})
# ---
# name: test_valid_config[sensor.mock_title_trains-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
@@ -367,3 +689,105 @@
'state': '1',
})
# ---
# name: test_valid_config[sensor.mock_title_trains_1-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_trains_1',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Trains +1',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Trains +1',
'platform': 'israel_rail',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'trains1',
'unique_id': 'באר יעקב אשקלון_trains1',
'unit_of_measurement': None,
})
# ---
# name: test_valid_config[sensor.mock_title_trains_1-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by Israel rail.',
'friendly_name': 'Mock Title Trains +1',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_trains_1',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '1',
})
# ---
# name: test_valid_config[sensor.mock_title_trains_2-entry]
EntityRegistryEntrySnapshot({
'aliases': list([
None,
]),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.mock_title_trains_2',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Trains +2',
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Trains +2',
'platform': 'israel_rail',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'trains2',
'unique_id': 'באר יעקב אשקלון_trains2',
'unit_of_measurement': None,
})
# ---
# name: test_valid_config[sensor.mock_title_trains_2-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by Israel rail.',
'friendly_name': 'Mock Title Trains +2',
}),
'context': <ANY>,
'entity_id': 'sensor.mock_title_trains_2',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '1',
})
# ---
+129 -16
View File
@@ -3,8 +3,10 @@
from unittest.mock import AsyncMock
from freezegun.api import FrozenDateTimeFactory
import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.components.israel_rail.const import DEPARTURES_COUNT
from homeassistant.const import STATE_UNAVAILABLE, STATE_UNKNOWN
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
@@ -12,7 +14,20 @@ from homeassistant.helpers import entity_registry as er
from . import goto_future, init_integration
from .conftest import TRAINS, get_time, get_train_route
from tests.common import MockConfigEntry, snapshot_platform
from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
# A moment just before the first train in TRAINS departs (10:10 UTC), so the
# coordinator considers the head of the list as an upcoming departure.
BEFORE_FIRST_TRAIN = "2021-10-10T10:00:00+00:00"
EXPECTED_ENTITY_COUNT = DEPARTURES_COUNT * 5
@pytest.fixture(autouse=True)
def freeze_before_first_train(freezer: FrozenDateTimeFactory) -> FrozenDateTimeFactory:
"""Freeze time before any train in TRAINS departs."""
freezer.move_to(BEFORE_FIRST_TRAIN)
return freezer
async def test_valid_config(
@@ -29,22 +44,23 @@ async def test_valid_config(
async def test_update_train(
hass: HomeAssistant,
freezer: FrozenDateTimeFactory,
freeze_before_first_train: FrozenDateTimeFactory,
mock_israelrail: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Ensure the train data is updated."""
await init_integration(hass, mock_config_entry)
assert len(hass.states.async_entity_ids()) == 7
assert len(hass.states.async_entity_ids()) == EXPECTED_ENTITY_COUNT
departure_sensor = hass.states.get("sensor.mock_title_departure")
expected_time = get_time(10, 10)
assert departure_sensor.state == expected_time
mock_israelrail.query.return_value = TRAINS[1:]
freeze_before_first_train.move_to("2021-10-10T10:15:00+00:00")
async_fire_time_changed(hass)
await hass.async_block_till_done()
await goto_future(hass, freezer)
assert len(hass.states.async_entity_ids()) == 7
assert len(hass.states.async_entity_ids()) == EXPECTED_ENTITY_COUNT
departure_sensor = hass.states.get("sensor.mock_title_departure")
expected_time = get_time(10, 20)
assert departure_sensor.state == expected_time
@@ -52,37 +68,37 @@ async def test_update_train(
async def test_fail_query(
hass: HomeAssistant,
freezer: FrozenDateTimeFactory,
freeze_before_first_train: FrozenDateTimeFactory,
mock_israelrail: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Ensure the integration handles query failures."""
await init_integration(hass, mock_config_entry)
assert len(hass.states.async_entity_ids()) == 7
assert len(hass.states.async_entity_ids()) == EXPECTED_ENTITY_COUNT
mock_israelrail.query.side_effect = Exception("error")
await goto_future(hass, freezer)
assert len(hass.states.async_entity_ids()) == 7
await goto_future(hass, freeze_before_first_train)
assert len(hass.states.async_entity_ids()) == EXPECTED_ENTITY_COUNT
departure_sensor = hass.states.get("sensor.mock_title_departure")
assert departure_sensor.state == STATE_UNAVAILABLE
async def test_no_departures(
hass: HomeAssistant,
freezer: FrozenDateTimeFactory,
freeze_before_first_train: FrozenDateTimeFactory,
mock_israelrail: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test handling when there are no departures available."""
await init_integration(hass, mock_config_entry)
assert len(hass.states.async_entity_ids()) == 7
assert len(hass.states.async_entity_ids()) == EXPECTED_ENTITY_COUNT
# Simulate no departures (e.g., after-hours)
mock_israelrail.query.return_value = []
await goto_future(hass, freezer)
await goto_future(hass, freeze_before_first_train)
# All sensors should still exist
assert len(hass.states.async_entity_ids()) == 7
assert len(hass.states.async_entity_ids()) == EXPECTED_ENTITY_COUNT
# Departure sensors should have unknown state (None)
departure_sensor = hass.states.get("sensor.mock_title_departure")
@@ -111,7 +127,7 @@ async def test_no_departures(
async def test_departure_delay(
hass: HomeAssistant,
freezer: FrozenDateTimeFactory,
freeze_before_first_train: FrozenDateTimeFactory,
mock_israelrail: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
@@ -132,7 +148,104 @@ async def test_departure_delay(
*TRAINS[1:],
]
await goto_future(hass, freezer)
# Refresh while still before TRAINS[0] departs, so the delay-bearing
# first route is treated as upcoming and not skipped.
freeze_before_first_train.move_to("2021-10-10T10:05:00+00:00")
async_fire_time_changed(hass)
await hass.async_block_till_done()
departure_delay_sensor = hass.states.get("sensor.mock_title_departure_delay")
assert departure_delay_sensor.state == "7"
async def test_skip_first_route_when_in_past(
hass: HomeAssistant,
freeze_before_first_train: FrozenDateTimeFactory,
mock_israelrail: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""When the first route already departed, sensors should reflect the next ones."""
# Freeze "now" between TRAINS[0] (10:10) and TRAINS[1] (10:20) so the head
# of the list is in the past. Coordinator should shift the window by 1.
freeze_before_first_train.move_to("2021-10-10T10:15:00+00:00")
await init_integration(hass, mock_config_entry)
# The +0/+1/+2 departure sensors should now show TRAINS[1], TRAINS[2], TRAINS[3].
assert hass.states.get("sensor.mock_title_departure").state == get_time(10, 20)
assert hass.states.get("sensor.mock_title_departure_1").state == get_time(10, 30)
assert hass.states.get("sensor.mock_title_departure_2").state == get_time(10, 40)
# The per-index sensors should also follow the shifted window — index 0
# now points at the second route in the API response, index 1 at the third, etc.
assert hass.states.get("sensor.mock_title_train_number").state == "1235"
assert hass.states.get("sensor.mock_title_train_number_1").state == "1236"
assert hass.states.get("sensor.mock_title_train_number_2").state == "1237"
async def test_keep_first_route_when_upcoming(
hass: HomeAssistant,
freeze_before_first_train: FrozenDateTimeFactory,
mock_israelrail: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""When the first route is still upcoming, sensors should keep it."""
# "now" sits well before TRAINS[0] (10:10), so no offset is applied.
await init_integration(hass, mock_config_entry)
assert hass.states.get("sensor.mock_title_departure").state == get_time(10, 10)
assert hass.states.get("sensor.mock_title_departure_1").state == get_time(10, 20)
assert hass.states.get("sensor.mock_title_departure_2").state == get_time(10, 30)
assert hass.states.get("sensor.mock_title_train_number").state == "1234"
async def test_skip_first_route_with_fewer_results(
hass: HomeAssistant,
freeze_before_first_train: FrozenDateTimeFactory,
mock_israelrail: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""A short result list with a past head still yields entries from the tail."""
# Only two routes; the first is already in the past so only one remains.
mock_israelrail.query.return_value = [TRAINS[0], TRAINS[1]]
freeze_before_first_train.move_to("2021-10-10T10:15:00+00:00")
await init_integration(hass, mock_config_entry)
assert hass.states.get("sensor.mock_title_departure").state == get_time(10, 20)
# No second/third routes available after the shift.
assert hass.states.get("sensor.mock_title_departure_1").state == STATE_UNKNOWN
assert hass.states.get("sensor.mock_title_departure_2").state == STATE_UNKNOWN
async def test_skip_multiple_past_routes(
hass: HomeAssistant,
freeze_before_first_train: FrozenDateTimeFactory,
mock_israelrail: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""When several routes at the head have already departed, the window shifts past them all."""
# Freeze "now" past TRAINS[0] (10:10) and TRAINS[1] (10:20) but before TRAINS[2] (10:30).
freeze_before_first_train.move_to("2021-10-10T10:25:00+00:00")
await init_integration(hass, mock_config_entry)
assert hass.states.get("sensor.mock_title_departure").state == get_time(10, 30)
assert hass.states.get("sensor.mock_title_departure_1").state == get_time(10, 40)
assert hass.states.get("sensor.mock_title_departure_2").state == get_time(10, 50)
assert hass.states.get("sensor.mock_title_train_number").state == "1236"
async def test_all_routes_in_past(
hass: HomeAssistant,
freeze_before_first_train: FrozenDateTimeFactory,
mock_israelrail: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""When every returned route has already departed, every departure sensor is unknown."""
freeze_before_first_train.move_to("2021-10-10T11:00:00+00:00")
await init_integration(hass, mock_config_entry)
assert hass.states.get("sensor.mock_title_departure").state == STATE_UNKNOWN
assert hass.states.get("sensor.mock_title_departure_1").state == STATE_UNKNOWN
assert hass.states.get("sensor.mock_title_departure_2").state == STATE_UNKNOWN