feat(proj): init

This commit is contained in:
vl.arkhangelskii
2026-09-21 04:06:43 +03:00
commit c956b94983
1076 changed files with 50876 additions and 0 deletions
+139
View File
@@ -0,0 +1,139 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:please_pay_me/app/app.dart';
import 'package:please_pay_me/core/config/app_config.dart';
import 'package:please_pay_me/core/storage/session_storage.dart';
import 'package:please_pay_me/data/demo/demo_backend.dart';
import 'package:please_pay_me/features/auth/session_controller.dart';
import 'package:please_pay_me/theme/theme.dart';
import 'support/test_setup.dart';
void main() {
setUpAll(setUpTestEnvironment);
SessionController demoSession({bool seeded = true}) {
return SessionController(
config: AppConfig.demo,
storage: InMemorySessionStorage(),
demoBackend: seeded ? DemoBackend() : DemoBackend.empty(),
);
}
/// Skeletons pulse forever, so `pumpAndSettle` would time out.
Future<void> settle(WidgetTester tester) async {
await tester.pump();
await tester.pump(const Duration(milliseconds: 400));
}
testWidgets('restoring session shows the branded splash', (tester) async {
final session = demoSession();
await tester.pumpWidget(PleasePayMeApp(session: session));
await tester.pump();
expect(find.text('Дожить до ЗП'), findsOneWidget);
expect(find.text('Бюджет от зарплаты до зарплаты'), findsOneWidget);
expect(find.byType(CupertinoActivityIndicator), findsOneWidget);
});
testWidgets('signed-out app shows the login screen', (tester) async {
final session = demoSession();
await session.restore();
await tester.pumpWidget(PleasePayMeApp(session: session));
await settle(tester);
expect(find.text('Дожить до ЗП'), findsOneWidget);
expect(find.text('Войти через Яндекс'), findsOneWidget);
});
testWidgets('demo session opens the overview with the current envelope',
(tester) async {
final session = demoSession()..startDemo();
await tester.pumpWidget(PleasePayMeApp(session: session));
await settle(tester);
expect(find.text('Обзор'), findsWidgets);
expect(find.text('До аванса'), findsOneWidget);
expect(find.text('Остаток бюджета'), findsOneWidget);
await tester.drag(find.byType(CustomScrollView).first, const Offset(0, -500));
await settle(tester);
// Grouped headers are uppercased by `AppSectionHeader`, as in iOS Settings.
expect(find.text('БЛИЖАЙШАЯ ВЫПЛАТА'), findsOneWidget);
expect(tester.takeException(), isNull);
});
testWidgets('tabs switch between the main sections', (tester) async {
final session = demoSession()..startDemo();
await tester.pumpWidget(PleasePayMeApp(session: session));
await settle(tester);
for (final tab in ['Журнал', 'Бюджеты', 'Работа', 'Профиль']) {
await tester.tap(find.text(tab).last);
await settle(tester);
expect(tester.takeException(), isNull, reason: 'tab $tab failed to render');
}
expect(find.text('Демо'), findsOneWidget);
});
testWidgets('profile theme switcher applies dark appearance', (tester) async {
final session = demoSession()..startDemo();
final theme = ThemeController(store: MemoryThemeStore());
await tester.pumpWidget(PleasePayMeApp(session: session, theme: theme));
await settle(tester);
await tester.tap(find.text('Профиль').last);
await settle(tester);
expect(find.text('Системная'), findsOneWidget);
expect(find.text('Светлая'), findsOneWidget);
await tester.tap(find.text('Тёмная'));
await settle(tester);
expect(theme.preference, ThemePreference.dark);
expect(theme.resolve(Brightness.light), Brightness.dark);
});
testWidgets('empty demo backend renders the empty states', (tester) async {
final session = demoSession(seeded: false)..startDemo();
await tester.pumpWidget(PleasePayMeApp(session: session));
await settle(tester);
expect(find.text('Бюджета пока нет'), findsOneWidget);
expect(find.text('Создать бюджет'), findsOneWidget);
});
testWidgets('recording an expense updates the remaining amount', (tester) async {
final session = demoSession()..startDemo();
await tester.pumpWidget(PleasePayMeApp(session: session));
await settle(tester);
await tester.tap(find.text('Добавить трату'));
await settle(tester);
expect(find.text('Новая трата'), findsOneWidget);
await tester.enterText(find.byType(CupertinoTextField).first, '1000');
await settle(tester);
await tester.tap(find.text('Записать трату'));
await tester.pump();
await tester.pump(const Duration(milliseconds: 500));
expect(find.text('Новая трата'), findsNothing);
expect(find.text('Трата записана'), findsOneWidget);
// Let the toast auto-dismiss so no timers outlive the test.
await tester.pump(const Duration(seconds: 3));
expect(tester.takeException(), isNull);
});
}