From be07463fbd8bdb8464cd0d6f48bf46678148061b Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 5 Dec 2023 15:06:05 -1000 Subject: [PATCH] dashboard: Add some basic tests for the dashboard (#5870) --- tests/dashboard/common.py | 6 ++ tests/dashboard/fixtures/conf/pico.yaml | 47 +++++++++++++++ tests/dashboard/test_web_server.py | 80 +++++++++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 tests/dashboard/common.py create mode 100644 tests/dashboard/fixtures/conf/pico.yaml create mode 100644 tests/dashboard/test_web_server.py diff --git a/tests/dashboard/common.py b/tests/dashboard/common.py new file mode 100644 index 0000000000..f84c03aad8 --- /dev/null +++ b/tests/dashboard/common.py @@ -0,0 +1,6 @@ +import pathlib + + +def get_fixture_path(filename: str) -> pathlib.Path: + """Get path of fixture.""" + return pathlib.Path(__file__).parent.joinpath("fixtures", filename) diff --git a/tests/dashboard/fixtures/conf/pico.yaml b/tests/dashboard/fixtures/conf/pico.yaml new file mode 100644 index 0000000000..cf5b5b75bf --- /dev/null +++ b/tests/dashboard/fixtures/conf/pico.yaml @@ -0,0 +1,47 @@ +substitutions: + name: picoproxy + friendly_name: Pico Proxy + +esphome: + name: ${name} + friendly_name: ${friendly_name} + project: + name: esphome.bluetooth-proxy + version: "1.0" + +esp32: + board: esp32dev + framework: + type: esp-idf + +wifi: + ap: + +api: +logger: +ota: +improv_serial: + +dashboard_import: + package_import_url: github://esphome/firmware/bluetooth-proxy/esp32-generic.yaml@main + +button: + - platform: factory_reset + id: resetf + - platform: safe_mode + name: Safe Mode Boot + entity_category: diagnostic + +sensor: + - platform: template + id: pm11 + name: "pm 1.0µm" + lambda: return 1.0; + - platform: template + id: pm251 + name: "pm 2.5µm" + lambda: return 2.5; + - platform: template + id: pm101 + name: "pm 10µm" + lambda: return 10; diff --git a/tests/dashboard/test_web_server.py b/tests/dashboard/test_web_server.py new file mode 100644 index 0000000000..a61850abf3 --- /dev/null +++ b/tests/dashboard/test_web_server.py @@ -0,0 +1,80 @@ +from __future__ import annotations + +import asyncio +import json +import os +from unittest.mock import Mock + +import pytest +import pytest_asyncio +from tornado.httpclient import AsyncHTTPClient, HTTPResponse +from tornado.httpserver import HTTPServer +from tornado.ioloop import IOLoop +from tornado.testing import bind_unused_port + +from esphome.dashboard import web_server +from esphome.dashboard.core import DASHBOARD + +from .common import get_fixture_path + + +class DashboardTestHelper: + def __init__(self, io_loop: IOLoop, client: AsyncHTTPClient, port: int) -> None: + self.io_loop = io_loop + self.client = client + self.port = port + + async def fetch(self, path: str, **kwargs) -> HTTPResponse: + """Get a response for the given path.""" + if path.lower().startswith(("http://", "https://")): + url = path + else: + url = f"http://127.0.0.1:{self.port}{path}" + future = self.client.fetch(url, raise_error=True, **kwargs) + result = await future + return result + + +@pytest_asyncio.fixture() +async def dashboard() -> DashboardTestHelper: + sock, port = bind_unused_port() + args = Mock( + ha_addon=True, + configuration=get_fixture_path("conf"), + port=port, + ) + DASHBOARD.settings.parse_args(args) + app = web_server.make_app() + http_server = HTTPServer(app) + http_server.add_sockets([sock]) + await DASHBOARD.async_setup() + os.environ["DISABLE_HA_AUTHENTICATION"] = "1" + assert DASHBOARD.settings.using_password is False + assert DASHBOARD.settings.on_ha_addon is True + assert DASHBOARD.settings.using_auth is False + task = asyncio.create_task(DASHBOARD.async_run()) + client = AsyncHTTPClient() + io_loop = IOLoop(make_current=False) + yield DashboardTestHelper(io_loop, client, port) + task.cancel() + sock.close() + client.close() + io_loop.close() + + +@pytest.mark.asyncio +async def test_main_page(dashboard: DashboardTestHelper) -> None: + response = await dashboard.fetch("/") + assert response.code == 200 + + +@pytest.mark.asyncio +async def test_devices_page(dashboard: DashboardTestHelper) -> None: + response = await dashboard.fetch("/devices") + assert response.code == 200 + assert response.headers["content-type"] == "application/json" + json_data = json.loads(response.body.decode()) + configured_devices = json_data["configured"] + first_device = configured_devices[0] + assert first_device["name"] == "pico" + assert first_device["configuration"] == "pico.yaml"