Skip to content

Commit 07493e5

Browse files
authored
Add missing tests for Nintendo Parental controls integration (home-assistant#154875)
1 parent 477073d commit 07493e5

File tree

6 files changed

+240
-3
lines changed

6 files changed

+240
-3
lines changed

homeassistant/components/nintendo_parental_controls/quality_scale.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ rules:
3636
entity-unavailable: todo
3737
integration-owner: done
3838
log-when-unavailable: done
39-
parallel-updates: todo
40-
reauthentication-flow: todo
41-
test-coverage: todo
39+
parallel-updates: done
40+
reauthentication-flow: done
41+
test-coverage: done
4242

4343
# Gold
4444
devices: done

tests/components/nintendo_parental_controls/conftest.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from pynintendoparental import NintendoParental
88
from pynintendoparental.device import Device
9+
from pynintendoparental.exceptions import InvalidOAuthConfigurationException
910
import pytest
1011

1112
from homeassistant.components.nintendo_parental_controls.const import DOMAIN
@@ -34,6 +35,7 @@ def mock_nintendo_device() -> Device:
3435
mock.extra = {"firmwareVersion": {"displayedVersion": "99.99.99"}}
3536
mock.limit_time = 120
3637
mock.today_playing_time = 110
38+
mock.today_time_remaining = 10
3739
mock.bedtime_alarm = time(hour=19)
3840
mock.set_bedtime_alarm.return_value = None
3941
mock.update_max_daily_playtime.return_value = None
@@ -73,6 +75,34 @@ def mock_nintendo_authenticator() -> Generator[MagicMock]:
7375
yield mock_auth
7476

7577

78+
@pytest.fixture
79+
def mock_failed_nintendo_authenticator() -> Generator[MagicMock]:
80+
"""Mock a failed Nintendo Authenticator."""
81+
with (
82+
patch(
83+
"homeassistant.components.nintendo_parental_controls.Authenticator",
84+
autospec=True,
85+
) as mock_auth_class,
86+
patch(
87+
"homeassistant.components.nintendo_parental_controls.config_flow.Authenticator",
88+
new=mock_auth_class,
89+
),
90+
patch(
91+
"homeassistant.components.nintendo_parental_controls.coordinator.NintendoParental.update",
92+
return_value=None,
93+
),
94+
):
95+
mock_auth = MagicMock()
96+
mock_auth.complete_login = AsyncMock(
97+
side_effect=InvalidOAuthConfigurationException(
98+
status_code=401,
99+
message="Authentication failed",
100+
)
101+
)
102+
mock_auth_class.complete_login = mock_auth.complete_login
103+
yield mock_auth
104+
105+
76106
@pytest.fixture
77107
def mock_nintendo_client(
78108
mock_nintendo_device: Device, mock_nintendo_authenticator: MagicMock
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# serializer version: 1
2+
# name: test_number[sensor.home_assistant_test_screen_time_remaining-entry]
3+
EntityRegistryEntrySnapshot({
4+
'aliases': set({
5+
}),
6+
'area_id': None,
7+
'capabilities': dict({
8+
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
9+
}),
10+
'config_entry_id': <ANY>,
11+
'config_subentry_id': <ANY>,
12+
'device_class': None,
13+
'device_id': <ANY>,
14+
'disabled_by': None,
15+
'domain': 'sensor',
16+
'entity_category': None,
17+
'entity_id': 'sensor.home_assistant_test_screen_time_remaining',
18+
'has_entity_name': True,
19+
'hidden_by': None,
20+
'icon': None,
21+
'id': <ANY>,
22+
'labels': set({
23+
}),
24+
'name': None,
25+
'options': dict({
26+
'sensor': dict({
27+
'suggested_display_precision': 2,
28+
}),
29+
}),
30+
'original_device_class': <SensorDeviceClass.DURATION: 'duration'>,
31+
'original_icon': None,
32+
'original_name': 'Screen time remaining',
33+
'platform': 'nintendo_parental_controls',
34+
'previous_unique_id': None,
35+
'suggested_object_id': None,
36+
'supported_features': 0,
37+
'translation_key': <NintendoParentalControlsSensor.TIME_REMAINING: 'time_remaining'>,
38+
'unique_id': 'testdevid_time_remaining',
39+
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
40+
})
41+
# ---
42+
# name: test_number[sensor.home_assistant_test_screen_time_remaining-state]
43+
StateSnapshot({
44+
'attributes': ReadOnlyDict({
45+
'device_class': 'duration',
46+
'friendly_name': 'Home Assistant Test Screen time remaining',
47+
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
48+
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
49+
}),
50+
'context': <ANY>,
51+
'entity_id': 'sensor.home_assistant_test_screen_time_remaining',
52+
'last_changed': <ANY>,
53+
'last_reported': <ANY>,
54+
'last_updated': <ANY>,
55+
'state': '10',
56+
})
57+
# ---
58+
# name: test_number[sensor.home_assistant_test_used_screen_time-entry]
59+
EntityRegistryEntrySnapshot({
60+
'aliases': set({
61+
}),
62+
'area_id': None,
63+
'capabilities': dict({
64+
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
65+
}),
66+
'config_entry_id': <ANY>,
67+
'config_subentry_id': <ANY>,
68+
'device_class': None,
69+
'device_id': <ANY>,
70+
'disabled_by': None,
71+
'domain': 'sensor',
72+
'entity_category': None,
73+
'entity_id': 'sensor.home_assistant_test_used_screen_time',
74+
'has_entity_name': True,
75+
'hidden_by': None,
76+
'icon': None,
77+
'id': <ANY>,
78+
'labels': set({
79+
}),
80+
'name': None,
81+
'options': dict({
82+
'sensor': dict({
83+
'suggested_display_precision': 2,
84+
}),
85+
}),
86+
'original_device_class': <SensorDeviceClass.DURATION: 'duration'>,
87+
'original_icon': None,
88+
'original_name': 'Used screen time',
89+
'platform': 'nintendo_parental_controls',
90+
'previous_unique_id': None,
91+
'suggested_object_id': None,
92+
'supported_features': 0,
93+
'translation_key': <NintendoParentalControlsSensor.PLAYING_TIME: 'playing_time'>,
94+
'unique_id': 'testdevid_playing_time',
95+
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
96+
})
97+
# ---
98+
# name: test_number[sensor.home_assistant_test_used_screen_time-state]
99+
StateSnapshot({
100+
'attributes': ReadOnlyDict({
101+
'device_class': 'duration',
102+
'friendly_name': 'Home Assistant Test Used screen time',
103+
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
104+
'unit_of_measurement': <UnitOfTime.MINUTES: 'min'>,
105+
}),
106+
'context': <ANY>,
107+
'entity_id': 'sensor.home_assistant_test_used_screen_time',
108+
'last_changed': <ANY>,
109+
'last_reported': <ANY>,
110+
'last_updated': <ANY>,
111+
'state': '110',
112+
})
113+
# ---
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""Test coordinator error handling."""
2+
3+
from unittest.mock import AsyncMock
4+
5+
from pynintendoparental.exceptions import InvalidOAuthConfigurationException
6+
7+
from homeassistant.config_entries import ConfigEntryState
8+
from homeassistant.core import HomeAssistant
9+
from homeassistant.helpers import entity_registry as er
10+
11+
from . import setup_integration
12+
13+
from tests.common import MockConfigEntry
14+
15+
16+
async def test_invalid_authentication(
17+
hass: HomeAssistant,
18+
mock_config_entry: MockConfigEntry,
19+
mock_nintendo_client: AsyncMock,
20+
entity_registry: er.EntityRegistry,
21+
) -> None:
22+
"""Test handling of invalid authentication."""
23+
mock_nintendo_client.update.side_effect = InvalidOAuthConfigurationException(
24+
status_code=401, message="Authentication failed"
25+
)
26+
27+
await setup_integration(hass, mock_config_entry)
28+
29+
# Ensure no entities are created
30+
entries = er.async_entries_for_config_entry(
31+
entity_registry, mock_config_entry.entry_id
32+
)
33+
assert len(entries) == 0
34+
# Ensure the config entry is marked as error
35+
assert mock_config_entry.state == ConfigEntryState.SETUP_ERROR
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""Test __init__ error handling."""
2+
3+
from unittest.mock import AsyncMock
4+
5+
from homeassistant.config_entries import ConfigEntryState
6+
from homeassistant.core import HomeAssistant
7+
from homeassistant.helpers import entity_registry as er
8+
9+
from . import setup_integration
10+
11+
from tests.common import MockConfigEntry
12+
13+
14+
async def test_invalid_authentication(
15+
hass: HomeAssistant,
16+
mock_config_entry: MockConfigEntry,
17+
mock_failed_nintendo_authenticator: AsyncMock,
18+
entity_registry: er.EntityRegistry,
19+
) -> None:
20+
"""Test handling of invalid authentication."""
21+
await setup_integration(hass, mock_config_entry)
22+
23+
# Ensure no entities are created
24+
entries = er.async_entries_for_config_entry(
25+
entity_registry, mock_config_entry.entry_id
26+
)
27+
assert len(entries) == 0
28+
# Ensure the config entry is marked as error
29+
assert mock_config_entry.state == ConfigEntryState.SETUP_ERROR
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"""Test sensor platform."""
2+
3+
from unittest.mock import AsyncMock, patch
4+
5+
from syrupy.assertion import SnapshotAssertion
6+
7+
from homeassistant.const import Platform
8+
from homeassistant.core import HomeAssistant
9+
from homeassistant.helpers import entity_registry as er
10+
11+
from . import setup_integration
12+
13+
from tests.common import MockConfigEntry, snapshot_platform
14+
15+
16+
async def test_number(
17+
hass: HomeAssistant,
18+
mock_config_entry: MockConfigEntry,
19+
mock_nintendo_client: AsyncMock,
20+
entity_registry: er.EntityRegistry,
21+
snapshot: SnapshotAssertion,
22+
) -> None:
23+
"""Test number platform."""
24+
with patch(
25+
"homeassistant.components.nintendo_parental_controls._PLATFORMS",
26+
[Platform.SENSOR],
27+
):
28+
await setup_integration(hass, mock_config_entry)
29+
30+
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)

0 commit comments

Comments
 (0)