Skip to content

Commit

Permalink
☔ Adds config_flow tests
Browse files Browse the repository at this point in the history
  • Loading branch information
frenck committed Feb 26, 2019
1 parent c69ea90 commit 192335e
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 0 deletions.
3 changes: 3 additions & 0 deletions requirements_test_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,9 @@ srpenergy==1.0.5
# homeassistant.components.statsd
statsd==3.2.1

# homeassistant.components.toon
toonapilib==3.0.9

# homeassistant.components.camera.uvc
uvcclient==0.11.0

Expand Down
1 change: 1 addition & 0 deletions script/gen_requirements_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
'sqlalchemy',
'srpenergy',
'statsd',
'toonapilib',
'uvcclient',
'vsure',
'warrant',
Expand Down
1 change: 1 addition & 0 deletions tests/components/toon/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Tests for the Toon component."""
177 changes: 177 additions & 0 deletions tests/components/toon/test_config_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
"""Tests for the Toon config flow."""

from unittest.mock import patch

import pytest
from toonapilib.toonapilibexceptions import (
AgreementsRetrievalError, InvalidConsumerKey, InvalidConsumerSecret,
InvalidCredentials)

from homeassistant import data_entry_flow
from homeassistant.components.toon import config_flow
from homeassistant.components.toon.const import (
CONF_CLIENT_ID, CONF_CLIENT_SECRET, CONF_DISPLAY, CONF_TENANT, DOMAIN)
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.setup import async_setup_component

from tests.common import MockConfigEntry, MockDependency

FIXTURE_APP = {
DOMAIN: {
CONF_CLIENT_ID: '1234567890abcdef',
CONF_CLIENT_SECRET: '1234567890abcdef',
}
}

FIXTURE_CREDENTIALS = {
CONF_USERNAME: 'john.doe',
CONF_PASSWORD: 'secret',
CONF_TENANT: 'eneco'
}

FIXTURE_DISPLAY = {
CONF_DISPLAY: 'display1'
}


@pytest.fixture
def mock_toonapilib():
"""Mock toonapilib."""
with MockDependency('toonapilib') as mock_toonapilib_:
mock_toonapilib_.Toon().display_names = [FIXTURE_DISPLAY[CONF_DISPLAY]]
yield mock_toonapilib_


async def setup_component(hass):
"""Set up Toon component."""
with patch('os.path.isfile', return_value=False):
assert await async_setup_component(hass, DOMAIN, FIXTURE_APP)
await hass.async_block_till_done()


async def test_abort_if_no_app_configured(hass):
"""Test abort if no app is configured."""
flow = config_flow.ToonFlowHandler()
flow.hass = hass
result = await flow.async_step_user()

assert result['type'] == data_entry_flow.RESULT_TYPE_ABORT
assert result['reason'] == 'no_app'


async def test_show_authenticate_form(hass):
"""Test that the authentication form is served."""
await setup_component(hass)

flow = config_flow.ToonFlowHandler()
flow.hass = hass
result = await flow.async_step_user(user_input=None)

assert result['type'] == data_entry_flow.RESULT_TYPE_FORM
assert result['step_id'] == 'authenticate'


@pytest.mark.parametrize('side_effect,reason',
[(InvalidConsumerKey, 'client_id'),
(InvalidConsumerSecret, 'client_secret'),
(AgreementsRetrievalError, 'no_agreements'),
(Exception, 'unknown_auth_fail')])
async def test_toon_abort(hass, mock_toonapilib, side_effect, reason):
"""Test we abort on Toon error."""
await setup_component(hass)

flow = config_flow.ToonFlowHandler()
flow.hass = hass

mock_toonapilib.Toon.side_effect = side_effect

result = await flow.async_step_authenticate(user_input=FIXTURE_CREDENTIALS)

assert result['type'] == data_entry_flow.RESULT_TYPE_ABORT
assert result['reason'] == reason


async def test_invalid_credentials(hass, mock_toonapilib):
"""Test we show authentication form on Toon auth error."""
mock_toonapilib.Toon.side_effect = InvalidCredentials

await setup_component(hass)

flow = config_flow.ToonFlowHandler()
flow.hass = hass
result = await flow.async_step_user(user_input=FIXTURE_CREDENTIALS)

assert result['type'] == data_entry_flow.RESULT_TYPE_FORM
assert result['step_id'] == 'authenticate'
assert result['errors'] == {'base': 'credentials'}


async def test_full_flow_implementation(hass, mock_toonapilib):
"""Test registering an integration and finishing flow works."""
await setup_component(hass)

flow = config_flow.ToonFlowHandler()
flow.hass = hass
result = await flow.async_step_user(user_input=None)
assert result['type'] == data_entry_flow.RESULT_TYPE_FORM
assert result['step_id'] == 'authenticate'

result = await flow.async_step_user(user_input=FIXTURE_CREDENTIALS)
assert result['type'] == data_entry_flow.RESULT_TYPE_FORM
assert result['step_id'] == 'display'

result = await flow.async_step_display(user_input=FIXTURE_DISPLAY)
assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result['title'] == FIXTURE_DISPLAY[CONF_DISPLAY]
assert result['data'][CONF_USERNAME] == FIXTURE_CREDENTIALS[CONF_USERNAME]
assert result['data'][CONF_PASSWORD] == FIXTURE_CREDENTIALS[CONF_PASSWORD]
assert result['data'][CONF_TENANT] == FIXTURE_CREDENTIALS[CONF_TENANT]
assert result['data'][CONF_DISPLAY] == FIXTURE_DISPLAY[CONF_DISPLAY]


async def test_no_displays(hass, mock_toonapilib):
"""Test abort when there are no displays."""
await setup_component(hass)

mock_toonapilib.Toon().display_names = []

flow = config_flow.ToonFlowHandler()
flow.hass = hass
await flow.async_step_user(user_input=FIXTURE_CREDENTIALS)

result = await flow.async_step_display(user_input=None)

assert result['type'] == data_entry_flow.RESULT_TYPE_ABORT
assert result['reason'] == 'no_displays'


async def test_display_already_exists(hass, mock_toonapilib):
"""Test showing display form again if display already exists."""
await setup_component(hass)

flow = config_flow.ToonFlowHandler()
flow.hass = hass
await flow.async_step_user(user_input=FIXTURE_CREDENTIALS)

MockConfigEntry(domain=DOMAIN, data=FIXTURE_DISPLAY).add_to_hass(hass)

result = await flow.async_step_display(user_input=FIXTURE_DISPLAY)

assert result['type'] == data_entry_flow.RESULT_TYPE_FORM
assert result['step_id'] == 'display'
assert result['errors'] == {'base': 'display_exists'}


async def test_abort_last_minute_fail(hass, mock_toonapilib):
"""Test we abort when API communication fails in the last step."""
await setup_component(hass)

flow = config_flow.ToonFlowHandler()
flow.hass = hass
await flow.async_step_user(user_input=FIXTURE_CREDENTIALS)

mock_toonapilib.Toon.side_effect = Exception

result = await flow.async_step_display(user_input=FIXTURE_DISPLAY)
assert result['type'] == data_entry_flow.RESULT_TYPE_ABORT
assert result['reason'] == 'unknown_auth_fail'

0 comments on commit 192335e

Please sign in to comment.