287 lines
9.0 KiB
Dart
287 lines
9.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:ignis_app/models/home_config.dart';
|
|
import 'package:ignis_app/screens/api_keys_screen.dart';
|
|
import 'package:ignis_app/screens/group_edit_screen.dart';
|
|
import 'package:ignis_app/screens/home_edit_screen.dart';
|
|
import 'package:ignis_app/screens/schedules_screen.dart';
|
|
import 'package:ignis_app/services/settings_service.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
import 'test_support.dart';
|
|
|
|
void main() {
|
|
TestWidgetsFlutterBinding.ensureInitialized();
|
|
|
|
testWidgets('schedules screen creates one-shot schedule for selected group', (
|
|
tester,
|
|
) async {
|
|
final api = FakeIgnisApi(
|
|
tasksData: {'tasks': <Object>[]},
|
|
groupsData: {
|
|
'bedroom': {'name': 'Спальня'},
|
|
},
|
|
);
|
|
|
|
await pumpTestApp(tester, child: const SchedulesScreen(), api: api);
|
|
await tester.pumpAndSettle();
|
|
|
|
await tester.tap(find.byIcon(Icons.add));
|
|
await tester.pumpAndSettle();
|
|
|
|
await tester.tap(find.byType(DropdownButtonFormField<String>));
|
|
await tester.pumpAndSettle();
|
|
await tester.tap(find.text('Спальня').last);
|
|
await tester.pumpAndSettle();
|
|
|
|
final createScheduleButton = find.widgetWithText(
|
|
ElevatedButton,
|
|
'СОЗДАТЬ РАСПИСАНИЕ',
|
|
);
|
|
await tester.ensureVisible(createScheduleButton);
|
|
await tester.tap(createScheduleButton);
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(api.scheduledOnceParams, isNotNull);
|
|
expect(api.scheduledOnceParams, containsPair('target_id', 'bedroom'));
|
|
expect(api.scheduledOnceParams, containsPair('is_group', true));
|
|
expect(api.scheduledOnceParams?['run_at'], isA<String>());
|
|
});
|
|
|
|
testWidgets('group edit screen auto-generates id and creates group', (
|
|
tester,
|
|
) async {
|
|
final api = FakeIgnisApi(
|
|
devicesData: {
|
|
'devices': [
|
|
{'mac': 'AA:BB', 'name': 'Лампа 1'},
|
|
],
|
|
},
|
|
groupsData: <Object>[],
|
|
);
|
|
|
|
await pumpTestApp(tester, child: const GroupEditScreen(), api: api);
|
|
await tester.pumpAndSettle();
|
|
|
|
await tester.enterText(
|
|
find.widgetWithText(TextFormField, 'Название группы'),
|
|
'Спальня родителей',
|
|
);
|
|
await tester.pump();
|
|
|
|
expect(find.text('spalnya-roditeley'), findsOneWidget);
|
|
|
|
await tester.tap(find.text('Лампа 1'));
|
|
await tester.pump();
|
|
|
|
await tester.tap(find.text('СОЗДАТЬ ГРУППУ'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(api.createdGroupId, 'spalnya-roditeley');
|
|
expect(api.createdGroupName, 'Спальня родителей');
|
|
expect(api.createdGroupMacs, ['AA:BB']);
|
|
});
|
|
|
|
testWidgets('group edit screen shows backend rescan summary', (tester) async {
|
|
final api =
|
|
FakeIgnisApi(
|
|
devicesData: {
|
|
'devices': [
|
|
{'mac': 'AA:BB', 'name': 'Лампа 1'},
|
|
],
|
|
},
|
|
groupsData: <Object>[],
|
|
)
|
|
..rescanNetworkData = {
|
|
'status': 'ok',
|
|
'found': 3,
|
|
'added': 1,
|
|
'updated': 2,
|
|
'removed_offline': 1,
|
|
'pending_removal': 0,
|
|
'online': 3,
|
|
};
|
|
|
|
await pumpTestApp(tester, child: const GroupEditScreen(), api: api);
|
|
await tester.pumpAndSettle();
|
|
|
|
await tester.tap(find.byTooltip('Пересканировать сеть'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(
|
|
find.text(
|
|
'Сканирование завершено: найдено 3, новых 1, обновлено 2, убрано 1',
|
|
),
|
|
findsOneWidget,
|
|
);
|
|
expect(api.rescanCalls, 1);
|
|
});
|
|
|
|
testWidgets('api keys screen validates and shows created key banner', (
|
|
tester,
|
|
) async {
|
|
final api = FakeIgnisApi(apiKeysData: {'keys': <Object>[]});
|
|
|
|
await pumpTestApp(tester, child: const ApiKeysScreen(), api: api);
|
|
await tester.pumpAndSettle();
|
|
|
|
await tester.tap(find.byIcon(Icons.add));
|
|
await tester.pumpAndSettle();
|
|
|
|
await tester.tap(find.text('Создать'));
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('Укажите имя ключа'), findsOneWidget);
|
|
|
|
await tester.enterText(
|
|
find.widgetWithText(TextFormField, 'Имя ключа'),
|
|
'Guest',
|
|
);
|
|
await tester.tap(find.text('Дать права администратора'));
|
|
await tester.pumpAndSettle();
|
|
await tester.tap(find.text('Создать'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(api.createdApiKeyName, 'Guest');
|
|
expect(api.createdApiKeyIsAdmin, isTrue);
|
|
expect(find.textContaining('Новый ключ создан'), findsOneWidget);
|
|
expect(find.textContaining('Guest_token'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('home edit screen validates fields and saves normalized home', (
|
|
tester,
|
|
) async {
|
|
tester.view.physicalSize = const Size(800, 1400);
|
|
tester.view.devicePixelRatio = 1;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
|
|
SharedPreferences.setMockInitialValues({});
|
|
final settingsService = SettingsService(
|
|
credentialsStorage: InMemoryCredentialsStorage(),
|
|
);
|
|
final api = FakeIgnisApi(authData: {'is_admin': true, 'name': 'owner'});
|
|
|
|
await pumpTestApp(
|
|
tester,
|
|
api: api,
|
|
settingsService: settingsService,
|
|
child: Builder(
|
|
builder: (context) => Scaffold(
|
|
body: Center(
|
|
child: ElevatedButton(
|
|
onPressed: () => Navigator.of(
|
|
context,
|
|
).push(MaterialPageRoute(builder: (_) => const HomeEditScreen())),
|
|
child: const Text('open'),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
|
|
await tester.tap(find.text('open'));
|
|
await tester.pumpAndSettle();
|
|
|
|
final saveHomeButton = find.widgetWithText(ElevatedButton, 'ДОБАВИТЬ');
|
|
await tester.tap(saveHomeButton);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('Укажите название дома'), findsOneWidget);
|
|
expect(find.text('Укажите адрес сервера'), findsOneWidget);
|
|
expect(find.text('Укажите API key'), findsOneWidget);
|
|
|
|
await tester.enterText(
|
|
find.widgetWithText(TextFormField, 'Название'),
|
|
'Квартира',
|
|
);
|
|
await tester.enterText(
|
|
find.widgetWithText(TextFormField, 'Адрес сервера'),
|
|
'ignis.akokos.ru/',
|
|
);
|
|
await tester.enterText(
|
|
find.widgetWithText(TextFormField, 'API Key'),
|
|
'secret-key',
|
|
);
|
|
await tester.enterText(
|
|
find.widgetWithText(TextFormField, 'Широта'),
|
|
'55.75',
|
|
);
|
|
await tester.enterText(
|
|
find.widgetWithText(TextFormField, 'Долгота'),
|
|
'37.61',
|
|
);
|
|
await tester.pump();
|
|
|
|
await tester.tap(saveHomeButton);
|
|
await tester.pumpAndSettle();
|
|
|
|
final homes = await settingsService.getHomes();
|
|
final savedHome = homes.single;
|
|
final savedApiKey = await settingsService.getHomeApiKey(savedHome.id);
|
|
|
|
expect(homes, hasLength(1));
|
|
expect(savedHome.name, 'Квартира');
|
|
expect(savedHome.url, 'https://ignis.akokos.ru');
|
|
expect(savedHome.latitude, 55.75);
|
|
expect(savedHome.longitude, 37.61);
|
|
expect(savedHome.geofenceEnabled, isFalse);
|
|
expect(
|
|
savedHome.geofenceRadiusMeters,
|
|
HomeConfig.defaultGeofenceRadiusMeters,
|
|
);
|
|
expect(savedApiKey, 'secret-key');
|
|
});
|
|
|
|
testWidgets('home edit screen keeps stored api key hidden on edit', (
|
|
tester,
|
|
) async {
|
|
SharedPreferences.setMockInitialValues({});
|
|
final settingsService = SettingsService(
|
|
credentialsStorage: InMemoryCredentialsStorage(),
|
|
);
|
|
final existingHome = HomeConfig(
|
|
id: 'home-1',
|
|
name: 'Квартира',
|
|
url: 'https://ignis.akokos.ru',
|
|
);
|
|
await settingsService.upsertHome(existingHome, apiKey: 'stored-secret');
|
|
|
|
final api = FakeIgnisApi(authData: {'is_admin': true, 'name': 'owner'});
|
|
|
|
await pumpTestApp(
|
|
tester,
|
|
api: api,
|
|
settingsService: settingsService,
|
|
child: HomeEditScreen(home: existingHome),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
|
|
final keyField = tester.widget<EditableText>(
|
|
find.byWidgetPredicate(
|
|
(widget) => widget is EditableText && widget.obscureText,
|
|
),
|
|
);
|
|
expect(keyField.controller.text, isEmpty);
|
|
expect(
|
|
find.text('Сохранённый ключ хранится отдельно и не показывается в поле'),
|
|
findsOneWidget,
|
|
);
|
|
|
|
await tester.enterText(
|
|
find.widgetWithText(TextFormField, 'Адрес сервера'),
|
|
'ignis.example.com',
|
|
);
|
|
await tester.pump();
|
|
|
|
await tester.tap(find.widgetWithText(ElevatedButton, 'СОХРАНИТЬ'));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(api.validateCredentialsCalls, 1);
|
|
expect(api.validatedBaseUrl, 'https://ignis.example.com');
|
|
expect(api.validatedApiKey, 'stored-secret');
|
|
expect(
|
|
await settingsService.getHomeApiKey(existingHome.id),
|
|
'stored-secret',
|
|
);
|
|
});
|
|
}
|