import 'package:flutter_test/flutter_test.dart'; import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart'; import 'package:halkyon_learn_flutter/src/core/router/route_paths.dart'; import 'package:halkyon_learn_flutter/src/core/widget/text_limits.dart'; import 'package:halkyon_learn_flutter/src/feature/card/data/card_repository.dart'; import 'package:halkyon_learn_flutter/src/feature/card/model/card_content.dart'; import 'package:halkyon_learn_flutter/src/feature/learning_path/data/learning_path_repository.dart'; import 'package:halkyon_learn_flutter/src/feature/learning_path/model/learning_path.dart'; import 'package:halkyon_learn_flutter/src/feature/note/data/note_repository.dart'; import 'package:halkyon_learn_flutter/src/feature/note/model/note_content.dart'; import 'package:halkyon_learn_flutter/src/feature/pomodoro/model/pomodoro_profile.dart'; import 'package:halkyon_learn_flutter/src/feature/settings/data/settings_repository.dart'; import 'package:halkyon_learn_flutter/src/feature/studyset/data/studyset_payload.dart'; import 'package:halkyon_learn_flutter/src/feature/studyset/model/studyset_content.dart'; import 'package:halkyon_learn_flutter/src/feature/tag/data/tag_repository.dart'; import 'package:material_ui/material_ui.dart'; import '../support/fake_card_gateway.dart'; import '../support/fake_learning_path_gateway.dart'; import '../support/fake_note_gateway.dart'; import '../support/fake_settings_gateway.dart'; import '../support/fake_studyset_gateway.dart'; import '../support/fake_tag_gateway.dart'; import '../support/pump_app.dart'; import '../support/test_dependencies.dart'; /// Names longer than the fields allow ([TextLimits]), as an older app, an /// import or another person's release can bring them: every screen that /// shows them cuts them short rather than overflowing, which fails a test. void main() { /// [length] characters of a name made of words, as long names are. String long(String word, int length) => List.filled(length, word).join(' ').substring(0, length); final studysetTitle = long('Japanese', TextLimits.title * 2); final kicker = long('日本語', TextLimits.secondary * 2); final topicTitle = long('Grammar', TextLimits.title * 2); final tagName = long('Particles', TextLimits.name * 3); final profileName = long('Deep focus', TextLimits.name * 3); late FakeStudysetGateway studysets; late FakeCardGateway cardGateway; late FakeNoteGateway noteGateway; late FakeLearningPathGateway pathGateway; late FakeTagGateway tagGateway; late FakeSettingsGateway settingsGateway; setUp(() async { studysets = FakeStudysetGateway() ..receiveRemoteChange( 'japanese', encodeStudysetPayload( StudysetContent( title: studysetTitle, secondaryTitle: kicker, description: RichContent.plain(long('About', 400)), ), ), ) ..receiveRemoteChange( 'grammar', encodeStudysetPayload(StudysetContent.titled(topicTitle)), parentId: 'japanese', ) ..receiveRemoteChange( 'inner', encodeStudysetPayload(StudysetContent.titled(topicTitle)), parentId: 'grammar', ); cardGateway = FakeCardGateway(); noteGateway = FakeNoteGateway(); pathGateway = FakeLearningPathGateway(); tagGateway = FakeTagGateway(); settingsGateway = FakeSettingsGateway(); final cards = CardRepository(cardGateway); final cardId = await cards.create( 'japanese', CardContent( front: RichContent.plain(long('front', 300)), back: RichContent.plain(long('back', 300)), ), ); final tags = TagRepository(tagGateway, cardChanges: cards.changes); await tags.setTagsOf(cardId, {await tags.create(tagName)}); await NoteRepository(noteGateway).create( 'japanese', NoteContent( title: long('Note', TextLimits.title * 2), body: RichContent.empty(), ), ); await LearningPathRepository(pathGateway).createPath( 'japanese', LearningPathContent.titled( long('Path', TextLimits.title * 2), ).withSecondaryTitle(long('Book', TextLimits.secondary * 2)), ); final profile = PomodoroProfile(id: 'long', name: profileName); await SettingsRepository(settingsGateway).update( (settings) => settings.withPomodoro( settings.pomodoro.withProfile(profile).withSelected(profile.id), ), ); await Future.wait([tags.dispose(), cards.dispose()]); }); for (final (window, width) in [('a phone', 360.0), ('a desktop', 1200.0)]) { Future show(WidgetTester tester, String location) async { tester.view.physicalSize = Size(width, 800); tester.view.devicePixelRatio = 1; addTearDown(tester.view.reset); await pumpApp( tester, testDependencies( studysetGateway: studysets, cardGateway: cardGateway, noteGateway: noteGateway, pathGateway: pathGateway, tagGateway: tagGateway, settingsGateway: settingsGateway, ), location: location, ); await tester.pump(const Duration(seconds: 1)); } testWidgets('on $window, Home with a long Pomodoro profile', ( tester, ) async { await show(tester, RoutePaths.home); expect(find.textContaining('Deep focus'), findsWidgets); await tester.tap(find.byTooltip(_profilesTooltip)); await tester.pumpAndSettle(); }); testWidgets('on $window, the library and a long studyset', ( tester, ) async { await show(tester, RoutePaths.library); expect(find.textContaining('Japanese'), findsWidgets); }); testWidgets("on $window, a long studyset's screen, its parts and topics", ( tester, ) async { await show(tester, RoutePaths.studyset('grammar')); for (final part in ['Study plan', 'Material']) { await openPart(tester, part); } if (width < 840) { await tester.tap(find.byTooltip('Show topics')); await tester.pumpAndSettle(); } }); testWidgets('on $window, the card browser with a long tag', ( tester, ) async { await show(tester, RoutePaths.cardBrowser('japanese')); await tester.tap(find.byTooltip('Detail')); await tester.pumpAndSettle(); await tester.tap(find.byTooltip('Select')); await tester.pumpAndSettle(); await tester.tap(find.byTooltip('More')); await tester.pumpAndSettle(); await tester.tap(find.text('Manage tags')); await tester.pumpAndSettle(); }); testWidgets('on $window, studying a long studyset', (tester) async { await show(tester, RoutePaths.study('japanese')); }); } } /// The tooltip of the Pomodoro card's profiles button. const _profilesTooltip = 'Pomodoro profiles';