import 'package:fintracker_app/core/glossary.dart'; import 'package:fintracker_app/core/widgets/help_tip.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; Widget _app(Widget child) => MaterialApp( home: Scaffold(body: Center(child: child)), ); void main() { test('the glossary finds a term regardless of case, spaces and «ё»', () { expect(glossaryHint('XIRR'), isNotNull); expect(glossaryHint(' xirr '), glossaryHint('XIRR')); expect(glossaryHint('Запас хода (runway)'), isNotNull); expect(glossaryHint('Внешний поток'), isNotNull); expect( glossaryHint('Счёт'), isNull, reason: 'an ordinary word is not a term', ); }); test('every explanation is a real sentence, not a stub', () { for (final label in [ 'XIRR', 'TWR', 'НКД', 'ЛДВ', 'Пассивный доход', 'Запас хода (runway)', ]) { final text = glossaryHint(label)!; expect(text.length, greaterThan(40), reason: label); expect(text.trim().endsWith('.'), isTrue, reason: label); } }); testWidgets('a known term carries a «?», an unknown label stays plain text', ( tester, ) async { await tester.pumpWidget( _app( const Column( mainAxisSize: MainAxisSize.min, children: [TermLabel('TWR'), TermLabel('Название')], ), ), ); expect(find.text('TWR'), findsOneWidget); expect(find.text('Название'), findsOneWidget); expect(find.byIcon(Icons.help_outline), findsOneWidget); }); testWidgets('an explicit hint wins over the glossary', (tester) async { await tester.pumpWidget( _app(const TermLabel('Прибыль', hint: 'Своё пояснение для налогов.')), ); final tip = tester.widget(find.byType(Tooltip)); expect(tip.message, 'Своё пояснение для налогов.'); }); testWidgets('hovering the «?» with a mouse shows the explanation', ( tester, ) async { await tester.pumpWidget(_app(const TermLabel('XIRR'))); final mouse = await tester.createGesture(kind: PointerDeviceKind.mouse); await mouse.addPointer(location: Offset.zero); addTearDown(mouse.removePointer); await mouse.moveTo(tester.getCenter(find.byIcon(Icons.help_outline))); await tester.pump(const Duration(milliseconds: 300)); await tester.pump(); expect( find.textContaining('годовая доходность с учётом дат'), findsOneWidget, ); }); testWidgets('a tap shows it too, for a phone with no hover', (tester) async { await tester.pumpWidget(_app(const TermLabel('НКД'))); await tester.tap(find.byIcon(Icons.help_outline)); await tester.pump(const Duration(milliseconds: 300)); expect(find.textContaining('накопленный купонный доход'), findsOneWidget); }); testWidgets('a numeric header keeps its label at the end of the cell', ( tester, ) async { await tester.pumpWidget( _app( const SizedBox( width: 200, child: TermLabel( 'XIRR', alignment: MainAxisAlignment.end, textAlign: TextAlign.end, ), ), ), ); final label = tester.getRect(find.text('XIRR')); final icon = tester.getRect(find.byIcon(Icons.help_outline)); expect( icon.left, greaterThanOrEqualTo(label.right), reason: 'the «?» follows the text', ); expect( icon.right, greaterThan(150), reason: 'and the pair hugs the right edge', ); }); }