Files
OnBudget/test/features/home/habit_chips_test.dart
T
SandersandClaude Opus 4.8 4f99b80169 Replace account_bindings with per-app default account; build analytics charts
Notification parsing:
- Drop the account_bindings table/DAO/repo/entity/controller/screen; account
  resolution now goes senderToAccount rule -> source_apps.defaultAccountId
  (trusted) -> global default (untrusted -> Inbox), via v1->v2 migration.
- Add defaultAccountId to source_apps; per-app settings consolidated into
  source_app_detail_screen (/settings/parsing/apps/:pkg).
- Inbox auto-learns an app default on first Confirm/CreateRule; account picker
  on the card instead of a disabled button; parse_error_labels extracted.

Analytics:
- Replace placeholder screen with fl_chart cards (chart_card, chart_theme,
  month_stepper, month_math domain helper); slim down habit_analysis_screen.

Android: add launcher icon (adaptive foreground + colors.xml) and app_name.

Tests: migration_v2, analytics (screen/month_math), AI retry, inbox
visibility; update resolver/gate/inbox suites for the new resolution path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-18 00:09:12 +03:00

76 lines
2.6 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:new_budget/l10n/app_localizations.dart';
import 'package:new_budget/src/app/theme/app_theme.dart';
import 'package:new_budget/src/core/database/converters/enum_converters.dart';
import 'package:new_budget/src/features/home/presentation/widgets/habit_chips.dart';
import 'package:new_budget/src/features/transactions/domain/entities/transaction.dart';
Transaction _tx({
SpendingObligation? obligation,
SpendingImpulse? impulse,
}) =>
Transaction(
id: 't',
userId: 'u',
accountId: 'a',
type: TransactionType.expense,
amount: 100,
date: DateTime(2026, 6, 1),
obligation: obligation,
impulse: impulse,
createdAt: DateTime(2026, 6, 1),
);
Widget _wrap(Transaction tx) => MaterialApp(
locale: const Locale('en'),
theme: AppTheme.light(),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: Scaffold(body: HabitChips(tx: tx)),
);
void main() {
setUpAll(() {
GoogleFonts.config.allowRuntimeFetching = false;
});
testWidgets('обе шкалы null → курсивное "not marked", без пилюль',
(tester) async {
await tester.pumpWidget(_wrap(_tx()));
final text = tester.widget<Text>(find.text('not marked'));
expect(text.style?.fontStyle, FontStyle.italic);
expect(find.byIcon(Icons.bolt), findsNothing);
});
testWidgets('considered не показывается ярлыком', (tester) async {
await tester.pumpWidget(_wrap(_tx(impulse: SpendingImpulse.considered)));
// Нет ярлыка импульса → пустое состояние.
expect(find.text('not marked'), findsOneWidget);
expect(find.byIcon(Icons.bolt), findsNothing);
});
testWidgets('obligation + impulsive рендерит обе пилюли с молнией',
(tester) async {
await tester.pumpWidget(_wrap(_tx(
obligation: SpendingObligation.required,
impulse: SpendingImpulse.impulsive,
)));
expect(find.text('Required'), findsOneWidget);
expect(find.text('Impulse'), findsOneWidget);
expect(find.byIcon(Icons.bolt), findsOneWidget);
expect(find.text('not marked'), findsNothing);
});
testWidgets('только obligation: пилюля без молнии', (tester) async {
await tester
.pumpWidget(_wrap(_tx(obligation: SpendingObligation.unnecessary)));
expect(find.text('Unnecessary'), findsOneWidget);
expect(find.byIcon(Icons.bolt), findsNothing);
});
}