feat: type remote device models
This commit is contained in:
@@ -2,10 +2,13 @@ import 'package:dio/dio.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:ignis_app/app/load_state.dart';
|
||||
import 'package:ignis_app/models/ignis_group.dart';
|
||||
import 'package:ignis_app/providers/providers.dart';
|
||||
import 'package:ignis_app/services/api_client.dart';
|
||||
|
||||
class FakeIgnisApi extends IgnisApi {
|
||||
Object? groupsData;
|
||||
Object? groupStatusData;
|
||||
Object? devicesData;
|
||||
Object? scenesData;
|
||||
Object? tasksData;
|
||||
@@ -18,6 +21,8 @@ class FakeIgnisApi extends IgnisApi {
|
||||
Object? statsError;
|
||||
Object? eventLogError;
|
||||
Object? apiKeysError;
|
||||
Object? groupsError;
|
||||
Object? groupStatusError;
|
||||
Object? controlGroupError;
|
||||
Object? cancelTaskError;
|
||||
Object? revokeApiKeyError;
|
||||
@@ -29,6 +34,8 @@ class FakeIgnisApi extends IgnisApi {
|
||||
String? revokedApiKey;
|
||||
|
||||
FakeIgnisApi({
|
||||
this.groupsData,
|
||||
this.groupStatusData,
|
||||
this.devicesData,
|
||||
this.scenesData,
|
||||
this.tasksData,
|
||||
@@ -59,9 +66,29 @@ class FakeIgnisApi extends IgnisApi {
|
||||
|
||||
@override
|
||||
Future<Response> getGroups() async {
|
||||
final error = groupsError;
|
||||
if (error != null) throw error;
|
||||
return Response(
|
||||
requestOptions: RequestOptions(path: '/devices/groups'),
|
||||
data: <Object>[],
|
||||
data: groupsData ?? <Object>[],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Response> getGroupStatus(String id) async {
|
||||
final error = groupStatusError;
|
||||
if (error != null) throw error;
|
||||
return Response(
|
||||
requestOptions: RequestOptions(path: '/control/group/$id/status'),
|
||||
data:
|
||||
groupStatusData ??
|
||||
{
|
||||
'results': [
|
||||
{
|
||||
'status': {'state': false, 'dimming': 100, 'temp': 4000},
|
||||
},
|
||||
],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -169,6 +196,20 @@ void main() {
|
||||
expect(api.requestedDays, 14);
|
||||
});
|
||||
|
||||
test('group status parser maps backend status shape', () {
|
||||
final state = IgnisGroupState.firstFromStatusResponse({
|
||||
'results': [
|
||||
{
|
||||
'status': {'state': true, 'dimming': 42, 'temp': 3000},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(state?.isOn, isTrue);
|
||||
expect(state?.brightness, 42);
|
||||
expect(state?.temp, 3000);
|
||||
});
|
||||
|
||||
test('devices load exposes data state', () async {
|
||||
final api = FakeIgnisApi(
|
||||
devicesData: {
|
||||
@@ -184,6 +225,8 @@ void main() {
|
||||
final state = container.read(devicesProvider);
|
||||
expect(state.status, LoadStatus.data);
|
||||
expect(state.data, hasLength(1));
|
||||
expect(state.data.single.groupMemberId, 'AA:BB');
|
||||
expect(state.data.single.name, 'Kitchen bulb');
|
||||
});
|
||||
|
||||
test('devices load exposes empty state', () async {
|
||||
@@ -309,7 +352,25 @@ void main() {
|
||||
final state = container.read(scenesProvider);
|
||||
expect(state.status, LoadStatus.data);
|
||||
expect(state.data, hasLength(2));
|
||||
expect(state.data.first, containsPair('id', 'party'));
|
||||
expect(state.data.first.id, 'party');
|
||||
expect(state.data.first.displayName, 'Party');
|
||||
});
|
||||
|
||||
test('scenes load maps numeric scene ids to display names', () async {
|
||||
final api = FakeIgnisApi(
|
||||
scenesData: {
|
||||
'scenes': ['1', '4'],
|
||||
},
|
||||
);
|
||||
final container = containerWith(api);
|
||||
|
||||
await container.read(scenesProvider.notifier).load();
|
||||
|
||||
final state = container.read(scenesProvider);
|
||||
expect(state.status, LoadStatus.data);
|
||||
expect(state.data.first.id, '1');
|
||||
expect(state.data.first.displayName, 'Океан');
|
||||
expect(state.data.last.displayName, 'Вечеринка');
|
||||
});
|
||||
|
||||
test('scenes load exposes empty state', () async {
|
||||
@@ -418,6 +479,44 @@ void main() {
|
||||
expect(state.errorMessage, contains('Backend недоступен'));
|
||||
});
|
||||
|
||||
test('groups refresh maps groups and status to typed state', () async {
|
||||
final api = FakeIgnisApi(
|
||||
groupsData: {
|
||||
'kitchen': {
|
||||
'name': 'Kitchen',
|
||||
'macs': ['AA:BB'],
|
||||
},
|
||||
},
|
||||
groupStatusData: {
|
||||
'results': [
|
||||
{
|
||||
'status': {
|
||||
'state': true,
|
||||
'dimming': 42,
|
||||
'temp': 3000,
|
||||
'r': 1,
|
||||
'g': 2,
|
||||
'b': 3,
|
||||
'scene': '4',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
);
|
||||
final container = containerWith(api);
|
||||
|
||||
await container.read(groupsProvider.notifier).refresh();
|
||||
|
||||
final groups = container.read(groupsProvider);
|
||||
expect(groups, hasLength(1));
|
||||
expect(groups.single.id, 'kitchen');
|
||||
expect(groups.single.name, 'Kitchen');
|
||||
expect(groups.single.macs, ['AA:BB']);
|
||||
expect(groups.single.state.isOn, isTrue);
|
||||
expect(groups.single.state.brightness, 42);
|
||||
expect(groups.single.state.sceneId, '4');
|
||||
});
|
||||
|
||||
test('task cancel error is not swallowed', () async {
|
||||
final api = FakeIgnisApi(tasksData: <Object>[]);
|
||||
final container = containerWith(api);
|
||||
|
||||
Reference in New Issue
Block a user