2016-03-09 09:25:50 +00:00
|
|
|
"""The tests for Home Assistant frontend."""
|
2017-03-30 07:50:53 +00:00
|
|
|
import asyncio
|
2015-01-30 07:56:04 +00:00
|
|
|
import re
|
2017-07-13 01:08:13 +00:00
|
|
|
from unittest.mock import patch
|
2015-01-30 07:56:04 +00:00
|
|
|
|
2017-03-30 07:50:53 +00:00
|
|
|
import pytest
|
2015-01-30 07:56:04 +00:00
|
|
|
|
2018-06-20 19:13:08 +00:00
|
|
|
from homeassistant.exceptions import HomeAssistantError
|
2017-03-30 07:50:53 +00:00
|
|
|
from homeassistant.setup import async_setup_component
|
2017-08-27 16:07:58 +00:00
|
|
|
from homeassistant.components.frontend import (
|
2017-11-29 06:53:12 +00:00
|
|
|
DOMAIN, CONF_JS_VERSION, CONF_THEMES, CONF_EXTRA_HTML_URL,
|
2018-06-05 14:50:16 +00:00
|
|
|
CONF_EXTRA_HTML_URL_ES5)
|
2018-05-01 17:35:23 +00:00
|
|
|
from homeassistant.components import websocket_api as wapi
|
2015-01-30 07:56:04 +00:00
|
|
|
|
2018-06-06 08:12:43 +00:00
|
|
|
from tests.common import mock_coro
|
|
|
|
|
|
|
|
|
|
|
|
CONFIG_THEMES = {
|
|
|
|
DOMAIN: {
|
|
|
|
CONF_THEMES: {
|
|
|
|
'happy': {
|
|
|
|
'primary-color': 'red'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-30 07:56:04 +00:00
|
|
|
|
2017-03-30 07:50:53 +00:00
|
|
|
@pytest.fixture
|
2018-03-15 20:49:49 +00:00
|
|
|
def mock_http_client(hass, aiohttp_client):
|
2017-03-30 07:50:53 +00:00
|
|
|
"""Start the Hass HTTP component."""
|
2017-05-19 14:37:39 +00:00
|
|
|
hass.loop.run_until_complete(async_setup_component(hass, 'frontend', {}))
|
2018-03-15 20:49:49 +00:00
|
|
|
return hass.loop.run_until_complete(aiohttp_client(hass.http.app))
|
2015-01-30 07:56:04 +00:00
|
|
|
|
|
|
|
|
2017-07-13 01:08:13 +00:00
|
|
|
@pytest.fixture
|
2018-03-15 20:49:49 +00:00
|
|
|
def mock_http_client_with_themes(hass, aiohttp_client):
|
2017-07-13 01:08:13 +00:00
|
|
|
"""Start the Hass HTTP component."""
|
|
|
|
hass.loop.run_until_complete(async_setup_component(hass, 'frontend', {
|
|
|
|
DOMAIN: {
|
2017-10-25 02:36:27 +00:00
|
|
|
CONF_THEMES: {
|
2017-07-13 01:08:13 +00:00
|
|
|
'happy': {
|
|
|
|
'primary-color': 'red'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}}))
|
2018-03-15 20:49:49 +00:00
|
|
|
return hass.loop.run_until_complete(aiohttp_client(hass.http.app))
|
2017-07-13 01:08:13 +00:00
|
|
|
|
|
|
|
|
2017-08-27 16:07:58 +00:00
|
|
|
@pytest.fixture
|
2018-03-15 20:49:49 +00:00
|
|
|
def mock_http_client_with_urls(hass, aiohttp_client):
|
2017-08-27 16:07:58 +00:00
|
|
|
"""Start the Hass HTTP component."""
|
|
|
|
hass.loop.run_until_complete(async_setup_component(hass, 'frontend', {
|
|
|
|
DOMAIN: {
|
2017-11-29 06:53:12 +00:00
|
|
|
CONF_JS_VERSION: 'auto',
|
|
|
|
CONF_EXTRA_HTML_URL: ["https://domain.com/my_extra_url.html"],
|
|
|
|
CONF_EXTRA_HTML_URL_ES5:
|
|
|
|
["https://domain.com/my_extra_url_es5.html"]
|
2017-08-27 16:07:58 +00:00
|
|
|
}}))
|
2018-03-15 20:49:49 +00:00
|
|
|
return hass.loop.run_until_complete(aiohttp_client(hass.http.app))
|
2017-08-27 16:07:58 +00:00
|
|
|
|
|
|
|
|
2017-03-30 07:50:53 +00:00
|
|
|
@asyncio.coroutine
|
|
|
|
def test_frontend_and_static(mock_http_client):
|
|
|
|
"""Test if we can get the frontend."""
|
|
|
|
resp = yield from mock_http_client.get('')
|
|
|
|
assert resp.status == 200
|
|
|
|
assert 'cache-control' not in resp.headers
|
2015-01-30 07:56:04 +00:00
|
|
|
|
2017-03-30 07:50:53 +00:00
|
|
|
text = yield from resp.text()
|
2015-01-30 07:56:04 +00:00
|
|
|
|
2017-03-30 07:50:53 +00:00
|
|
|
# Test we can retrieve frontend.js
|
|
|
|
frontendjs = re.search(
|
2018-07-26 08:25:57 +00:00
|
|
|
r'(?P<app>\/frontend_es5\/app-[A-Za-z0-9]{8}.js)', text)
|
2015-01-30 07:56:04 +00:00
|
|
|
|
2017-03-30 07:50:53 +00:00
|
|
|
assert frontendjs is not None
|
|
|
|
resp = yield from mock_http_client.get(frontendjs.groups(0)[0])
|
|
|
|
assert resp.status == 200
|
|
|
|
assert 'public' in resp.headers.get('cache-control')
|
2015-01-30 07:56:04 +00:00
|
|
|
|
|
|
|
|
2017-03-30 07:50:53 +00:00
|
|
|
@asyncio.coroutine
|
|
|
|
def test_dont_cache_service_worker(mock_http_client):
|
|
|
|
"""Test that we don't cache the service worker."""
|
2017-11-11 07:02:06 +00:00
|
|
|
resp = yield from mock_http_client.get('/service_worker_es5.js')
|
|
|
|
assert resp.status == 200
|
|
|
|
assert 'cache-control' not in resp.headers
|
|
|
|
|
2017-03-30 07:50:53 +00:00
|
|
|
resp = yield from mock_http_client.get('/service_worker.js')
|
|
|
|
assert resp.status == 200
|
|
|
|
assert 'cache-control' not in resp.headers
|
2015-01-30 07:56:04 +00:00
|
|
|
|
|
|
|
|
2017-03-30 07:50:53 +00:00
|
|
|
@asyncio.coroutine
|
|
|
|
def test_404(mock_http_client):
|
|
|
|
"""Test for HTTP 404 error."""
|
|
|
|
resp = yield from mock_http_client.get('/not-existing')
|
|
|
|
assert resp.status == 404
|
2016-05-14 07:58:36 +00:00
|
|
|
|
2015-01-30 07:56:04 +00:00
|
|
|
|
2017-03-30 07:50:53 +00:00
|
|
|
@asyncio.coroutine
|
|
|
|
def test_we_cannot_POST_to_root(mock_http_client):
|
|
|
|
"""Test that POST is not allow to root."""
|
|
|
|
resp = yield from mock_http_client.post('/')
|
|
|
|
assert resp.status == 405
|
2015-01-30 07:56:04 +00:00
|
|
|
|
|
|
|
|
2017-03-30 07:50:53 +00:00
|
|
|
@asyncio.coroutine
|
2017-07-13 01:08:13 +00:00
|
|
|
def test_states_routes(mock_http_client):
|
2017-03-30 07:50:53 +00:00
|
|
|
"""All served by index."""
|
|
|
|
resp = yield from mock_http_client.get('/states')
|
|
|
|
assert resp.status == 200
|
2015-01-30 07:56:04 +00:00
|
|
|
|
2017-03-30 07:50:53 +00:00
|
|
|
resp = yield from mock_http_client.get('/states/group.existing')
|
|
|
|
assert resp.status == 200
|
2017-07-13 01:08:13 +00:00
|
|
|
|
|
|
|
|
2018-06-06 08:12:43 +00:00
|
|
|
async def test_themes_api(hass, hass_ws_client):
|
2017-07-13 01:08:13 +00:00
|
|
|
"""Test that /api/themes returns correct data."""
|
2018-06-06 08:12:43 +00:00
|
|
|
assert await async_setup_component(hass, 'frontend', CONFIG_THEMES)
|
|
|
|
client = await hass_ws_client(hass)
|
|
|
|
|
|
|
|
await client.send_json({
|
|
|
|
'id': 5,
|
|
|
|
'type': 'frontend/get_themes',
|
|
|
|
})
|
|
|
|
msg = await client.receive_json()
|
2017-07-13 01:08:13 +00:00
|
|
|
|
2018-06-06 08:12:43 +00:00
|
|
|
assert msg['result']['default_theme'] == 'default'
|
|
|
|
assert msg['result']['themes'] == {'happy': {'primary-color': 'red'}}
|
2017-07-13 01:08:13 +00:00
|
|
|
|
2018-06-06 08:12:43 +00:00
|
|
|
|
|
|
|
async def test_themes_set_theme(hass, hass_ws_client):
|
2017-07-13 01:08:13 +00:00
|
|
|
"""Test frontend.set_theme service."""
|
2018-06-06 08:12:43 +00:00
|
|
|
assert await async_setup_component(hass, 'frontend', CONFIG_THEMES)
|
|
|
|
client = await hass_ws_client(hass)
|
2017-07-13 01:08:13 +00:00
|
|
|
|
2018-06-06 08:12:43 +00:00
|
|
|
await hass.services.async_call(
|
|
|
|
DOMAIN, 'set_theme', {'name': 'happy'}, blocking=True)
|
2017-07-13 01:08:13 +00:00
|
|
|
|
2018-06-06 08:12:43 +00:00
|
|
|
await client.send_json({
|
|
|
|
'id': 5,
|
|
|
|
'type': 'frontend/get_themes',
|
|
|
|
})
|
|
|
|
msg = await client.receive_json()
|
2017-07-13 01:08:13 +00:00
|
|
|
|
2018-06-06 08:12:43 +00:00
|
|
|
assert msg['result']['default_theme'] == 'happy'
|
|
|
|
|
|
|
|
await hass.services.async_call(
|
|
|
|
DOMAIN, 'set_theme', {'name': 'default'}, blocking=True)
|
|
|
|
|
|
|
|
await client.send_json({
|
|
|
|
'id': 6,
|
|
|
|
'type': 'frontend/get_themes',
|
|
|
|
})
|
|
|
|
msg = await client.receive_json()
|
|
|
|
|
|
|
|
assert msg['result']['default_theme'] == 'default'
|
|
|
|
|
|
|
|
|
|
|
|
async def test_themes_set_theme_wrong_name(hass, hass_ws_client):
|
2017-07-13 01:08:13 +00:00
|
|
|
"""Test frontend.set_theme service called with wrong name."""
|
2018-06-06 08:12:43 +00:00
|
|
|
assert await async_setup_component(hass, 'frontend', CONFIG_THEMES)
|
|
|
|
client = await hass_ws_client(hass)
|
2017-07-13 01:08:13 +00:00
|
|
|
|
2018-06-06 08:12:43 +00:00
|
|
|
await hass.services.async_call(
|
|
|
|
DOMAIN, 'set_theme', {'name': 'wrong'}, blocking=True)
|
2017-07-13 01:08:13 +00:00
|
|
|
|
2018-06-06 08:12:43 +00:00
|
|
|
await client.send_json({
|
|
|
|
'id': 5,
|
|
|
|
'type': 'frontend/get_themes',
|
|
|
|
})
|
|
|
|
|
|
|
|
msg = await client.receive_json()
|
|
|
|
|
|
|
|
assert msg['result']['default_theme'] == 'default'
|
|
|
|
|
|
|
|
|
|
|
|
async def test_themes_reload_themes(hass, hass_ws_client):
|
2017-07-13 01:08:13 +00:00
|
|
|
"""Test frontend.reload_themes service."""
|
2018-06-06 08:12:43 +00:00
|
|
|
assert await async_setup_component(hass, 'frontend', CONFIG_THEMES)
|
|
|
|
client = await hass_ws_client(hass)
|
|
|
|
|
2017-07-13 01:08:13 +00:00
|
|
|
with patch('homeassistant.components.frontend.load_yaml_config_file',
|
|
|
|
return_value={DOMAIN: {
|
2017-10-25 02:36:27 +00:00
|
|
|
CONF_THEMES: {
|
2017-07-13 01:08:13 +00:00
|
|
|
'sad': {'primary-color': 'blue'}
|
|
|
|
}}}):
|
2018-06-06 08:12:43 +00:00
|
|
|
await hass.services.async_call(
|
|
|
|
DOMAIN, 'set_theme', {'name': 'happy'}, blocking=True)
|
|
|
|
await hass.services.async_call(DOMAIN, 'reload_themes', blocking=True)
|
2017-07-14 18:26:26 +00:00
|
|
|
|
2018-06-06 08:12:43 +00:00
|
|
|
await client.send_json({
|
|
|
|
'id': 5,
|
|
|
|
'type': 'frontend/get_themes',
|
|
|
|
})
|
2017-07-14 18:26:26 +00:00
|
|
|
|
2018-06-06 08:12:43 +00:00
|
|
|
msg = await client.receive_json()
|
|
|
|
|
|
|
|
assert msg['result']['themes'] == {'sad': {'primary-color': 'blue'}}
|
|
|
|
assert msg['result']['default_theme'] == 'default'
|
|
|
|
|
|
|
|
|
|
|
|
async def test_missing_themes(hass, hass_ws_client):
|
2017-07-14 18:26:26 +00:00
|
|
|
"""Test that themes API works when themes are not defined."""
|
2018-06-06 08:12:43 +00:00
|
|
|
await async_setup_component(hass, 'frontend')
|
|
|
|
|
|
|
|
client = await hass_ws_client(hass)
|
|
|
|
await client.send_json({
|
|
|
|
'id': 5,
|
|
|
|
'type': 'frontend/get_themes',
|
|
|
|
})
|
|
|
|
|
|
|
|
msg = await client.receive_json()
|
|
|
|
|
|
|
|
assert msg['id'] == 5
|
|
|
|
assert msg['type'] == wapi.TYPE_RESULT
|
|
|
|
assert msg['success']
|
|
|
|
assert msg['result']['default_theme'] == 'default'
|
|
|
|
assert msg['result']['themes'] == {}
|
2017-08-27 16:07:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
@asyncio.coroutine
|
|
|
|
def test_extra_urls(mock_http_client_with_urls):
|
|
|
|
"""Test that extra urls are loaded."""
|
2017-11-29 06:53:12 +00:00
|
|
|
resp = yield from mock_http_client_with_urls.get('/states?latest')
|
2017-08-27 16:07:58 +00:00
|
|
|
assert resp.status == 200
|
|
|
|
text = yield from resp.text()
|
2018-07-26 08:25:57 +00:00
|
|
|
assert text.find("href='https://domain.com/my_extra_url.html'") >= 0
|
2017-08-31 04:21:24 +00:00
|
|
|
|
|
|
|
|
2017-11-29 06:53:12 +00:00
|
|
|
@asyncio.coroutine
|
|
|
|
def test_extra_urls_es5(mock_http_client_with_urls):
|
|
|
|
"""Test that es5 extra urls are loaded."""
|
|
|
|
resp = yield from mock_http_client_with_urls.get('/states?es5')
|
|
|
|
assert resp.status == 200
|
|
|
|
text = yield from resp.text()
|
2018-07-26 08:25:57 +00:00
|
|
|
assert text.find("href='https://domain.com/my_extra_url_es5.html'") >= 0
|
2017-11-29 06:53:12 +00:00
|
|
|
|
|
|
|
|
2018-05-01 17:35:23 +00:00
|
|
|
async def test_get_panels(hass, hass_ws_client):
|
|
|
|
"""Test get_panels command."""
|
|
|
|
await async_setup_component(hass, 'frontend')
|
|
|
|
await hass.components.frontend.async_register_built_in_panel(
|
|
|
|
'map', 'Map', 'mdi:account-location')
|
|
|
|
|
|
|
|
client = await hass_ws_client(hass)
|
|
|
|
await client.send_json({
|
|
|
|
'id': 5,
|
|
|
|
'type': 'get_panels',
|
|
|
|
})
|
|
|
|
|
|
|
|
msg = await client.receive_json()
|
|
|
|
|
|
|
|
assert msg['id'] == 5
|
|
|
|
assert msg['type'] == wapi.TYPE_RESULT
|
|
|
|
assert msg['success']
|
|
|
|
assert msg['result']['map']['component_name'] == 'map'
|
|
|
|
assert msg['result']['map']['url_path'] == 'map'
|
|
|
|
assert msg['result']['map']['icon'] == 'mdi:account-location'
|
|
|
|
assert msg['result']['map']['title'] == 'Map'
|
2018-06-06 08:12:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_get_translations(hass, hass_ws_client):
|
|
|
|
"""Test get_translations command."""
|
|
|
|
await async_setup_component(hass, 'frontend')
|
|
|
|
client = await hass_ws_client(hass)
|
|
|
|
|
|
|
|
with patch('homeassistant.components.frontend.async_get_translations',
|
|
|
|
side_effect=lambda hass, lang: mock_coro({'lang': lang})):
|
|
|
|
await client.send_json({
|
|
|
|
'id': 5,
|
|
|
|
'type': 'frontend/get_translations',
|
|
|
|
'language': 'nl',
|
|
|
|
})
|
|
|
|
msg = await client.receive_json()
|
|
|
|
|
|
|
|
assert msg['id'] == 5
|
|
|
|
assert msg['type'] == wapi.TYPE_RESULT
|
|
|
|
assert msg['success']
|
|
|
|
assert msg['result'] == {'resources': {'lang': 'nl'}}
|
2018-06-16 21:12:03 +00:00
|
|
|
|
|
|
|
|
2018-06-20 19:13:08 +00:00
|
|
|
async def test_lovelace_ui(hass, hass_ws_client):
|
|
|
|
"""Test lovelace_ui command."""
|
2018-06-16 21:12:03 +00:00
|
|
|
await async_setup_component(hass, 'frontend')
|
|
|
|
client = await hass_ws_client(hass)
|
|
|
|
|
|
|
|
with patch('homeassistant.components.frontend.load_yaml',
|
|
|
|
return_value={'hello': 'world'}):
|
|
|
|
await client.send_json({
|
|
|
|
'id': 5,
|
2018-06-20 19:13:08 +00:00
|
|
|
'type': 'frontend/lovelace_config',
|
2018-06-16 21:12:03 +00:00
|
|
|
})
|
|
|
|
msg = await client.receive_json()
|
|
|
|
|
|
|
|
assert msg['id'] == 5
|
|
|
|
assert msg['type'] == wapi.TYPE_RESULT
|
|
|
|
assert msg['success']
|
|
|
|
assert msg['result'] == {'hello': 'world'}
|
2018-06-20 19:13:08 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_lovelace_ui_not_found(hass, hass_ws_client):
|
|
|
|
"""Test lovelace_ui command cannot find file."""
|
|
|
|
await async_setup_component(hass, 'frontend')
|
|
|
|
client = await hass_ws_client(hass)
|
|
|
|
|
|
|
|
with patch('homeassistant.components.frontend.load_yaml',
|
|
|
|
side_effect=FileNotFoundError):
|
|
|
|
await client.send_json({
|
|
|
|
'id': 5,
|
|
|
|
'type': 'frontend/lovelace_config',
|
|
|
|
})
|
|
|
|
msg = await client.receive_json()
|
|
|
|
|
|
|
|
assert msg['id'] == 5
|
|
|
|
assert msg['type'] == wapi.TYPE_RESULT
|
|
|
|
assert msg['success'] is False
|
|
|
|
assert msg['error']['code'] == 'file_not_found'
|
|
|
|
|
|
|
|
|
|
|
|
async def test_lovelace_ui_load_err(hass, hass_ws_client):
|
|
|
|
"""Test lovelace_ui command cannot find file."""
|
|
|
|
await async_setup_component(hass, 'frontend')
|
|
|
|
client = await hass_ws_client(hass)
|
|
|
|
|
|
|
|
with patch('homeassistant.components.frontend.load_yaml',
|
|
|
|
side_effect=HomeAssistantError):
|
|
|
|
await client.send_json({
|
|
|
|
'id': 5,
|
|
|
|
'type': 'frontend/lovelace_config',
|
|
|
|
})
|
|
|
|
msg = await client.receive_json()
|
|
|
|
|
|
|
|
assert msg['id'] == 5
|
|
|
|
assert msg['type'] == wapi.TYPE_RESULT
|
|
|
|
assert msg['success'] is False
|
|
|
|
assert msg['error']['code'] == 'load_error'
|
2018-07-22 07:49:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_auth_load(mock_http_client):
|
|
|
|
"""Test auth component loaded by default."""
|
|
|
|
resp = await mock_http_client.get('/auth/providers')
|
|
|
|
assert resp.status == 200
|
|
|
|
|
|
|
|
|
|
|
|
async def test_onboarding_load(mock_http_client):
|
|
|
|
"""Test onboarding component loaded by default."""
|
|
|
|
resp = await mock_http_client.get('/api/onboarding')
|
|
|
|
assert resp.status == 200
|