Files
homeassistant_espscreen/tests/test_page_assets.py
T
Max Gramser d6e5b35dcf Add a card for blinds and curtains, and fix what Studio 1 showed after 0.2.57 (0.2.58)
A tap on a cover now opens a card like Home Assistant's own, in the style
of the climate and vacuum cards: a tall position slider on which the blind
hangs from the top, a tilt slider over slats for venetian blinds, and open,
stop and close keys. The key of the direction the cover moves is filled; a
key that cannot move it further is disabled and stays out of the keys the
card's tick enables. Sliders show their value while dragged and send it on
release. The card offers only what supported_features allows. A
battery-powered blind shows its battery at the top right: the app sends
the device's battery sensor as the extra the vacuum card uses, and adds
current_tilt_position to the attributes.

Checking Studio 1 after its update to firmware 0.2.49 found that a setting
number equal to its initial state 0 (night brightness 0 %) was never
published, so Home Assistant kept it unknown and ESP Screens could not
change it; apply_screen_settings now publishes a number without a state.
The app also took "unavailable" for the device name during the restart
and wrote sensor.esp_screens_unavailable; diagnostics ignore unknown and
unavailable. The editor redraws its tiles, top bar and entity list when
the live stream opened a screen before the first full inventory (a busy
add-on), and loads app.js and style.css by content stamp after Safari kept
an old script.

Checked with 254 Python and 14 C++ tests, generate_packages --check, ESP32
builds of both profiles, and 20 API checks of the card on host builds of
both boards. Firmware 0.2.50.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 16:41:10 +02:00

44 lines
2.1 KiB
Python

"""The page loads its own script and styles by content stamp (app 0.2.58).
After updating to 0.2.57, Safari showed an empty Screen settings panel: it kept a cached script from before
the update. The page now asks for app.js and style.css with a stamp of their content, so a new version is
always fetched and an old one is never combined with a new page.
"""
import hashlib
import importlib.util
import tempfile
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
STATIC = ROOT / 'screen_manager/app/static'
HAS_AIOHTTP = importlib.util.find_spec('aiohttp') is not None
@unittest.skipUnless(HAS_AIOHTTP, 'Run using .venv-portal/bin/python for server tests')
class Assets(unittest.IsolatedAsyncioTestCase):
async def test_script_and_styles_carry_a_stamp_of_their_content(self):
import sys
sys.path.insert(0, str(ROOT / 'screen_manager/app'))
sys.path.insert(0, str(ROOT / 'tests'))
import test_scaling
from aiohttp.test_utils import TestClient, TestServer
from server import Manager, create_app
stamp = hashlib.sha1((STATIC / 'app.js').read_bytes() + (STATIC / 'style.css').read_bytes()).hexdigest()[:12]
with tempfile.TemporaryDirectory() as tmp:
manager = Manager(test_scaling.fake_ha(), Path(tmp) / 'screens.json')
async with TestClient(TestServer(create_app(manager, True))) as client:
response = await client.get('/')
page = await response.text()
self.assertEqual(response.status, 200)
self.assertIn(f'<script src="static/app.js?v={stamp}" defer></script>', page)
self.assertIn(f'<link rel="stylesheet" href="static/style.css?v={stamp}" />', page)
self.assertEqual(response.headers['Cache-Control'], 'no-store')
self.assertIn('text/html', response.headers['Content-Type'])
script = await client.get(f'/static/app.js?v={stamp}')
self.assertEqual((script.status, await script.read()), (200, (STATIC / 'app.js').read_bytes()))
if __name__ == '__main__':
unittest.main()