From 0a3aa4caa0216234903a0a823611616acada40c6 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Wed, 27 Nov 2024 16:16:55 +0100 Subject: [PATCH] test(neon_rich_text): Separate all tests into multiple files Signed-off-by: provokateurin --- .../test/rich_objects/deck_card_test.dart | 59 ++ .../test/rich_objects/fallback_test.dart | 103 +++ .../test/rich_objects/file_test.dart | 253 +++++++ .../goldens/rich_text_object_deck_card.png | Bin .../rich_text_object_fallback_with_icon.png | Bin ...rich_text_object_fallback_without_icon.png | Bin .../goldens/rich_text_object_mention_call.png | Bin .../rich_text_object_mention_guest.png | Bin ...xt_object_mention_user-group_highlight.png | Bin ...h_text_object_mention_user-group_other.png | Bin ...ich_text_object_mention_user_highlight.png | Bin .../rich_text_object_mention_user_other.png | Bin .../test/rich_objects/mention_test.dart | 181 +++++ .../test/rich_objects/rich_objects_test.dart | 143 ++++ .../neon_rich_text/test/rich_text_test.dart | 634 ------------------ 15 files changed, 739 insertions(+), 634 deletions(-) create mode 100644 packages/neon_framework/packages/neon_rich_text/test/rich_objects/deck_card_test.dart create mode 100644 packages/neon_framework/packages/neon_rich_text/test/rich_objects/fallback_test.dart create mode 100644 packages/neon_framework/packages/neon_rich_text/test/rich_objects/file_test.dart rename packages/neon_framework/packages/neon_rich_text/test/{ => rich_objects}/goldens/rich_text_object_deck_card.png (100%) rename packages/neon_framework/packages/neon_rich_text/test/{ => rich_objects}/goldens/rich_text_object_fallback_with_icon.png (100%) rename packages/neon_framework/packages/neon_rich_text/test/{ => rich_objects}/goldens/rich_text_object_fallback_without_icon.png (100%) rename packages/neon_framework/packages/neon_rich_text/test/{ => rich_objects}/goldens/rich_text_object_mention_call.png (100%) rename packages/neon_framework/packages/neon_rich_text/test/{ => rich_objects}/goldens/rich_text_object_mention_guest.png (100%) rename packages/neon_framework/packages/neon_rich_text/test/{ => rich_objects}/goldens/rich_text_object_mention_user-group_highlight.png (100%) rename packages/neon_framework/packages/neon_rich_text/test/{ => rich_objects}/goldens/rich_text_object_mention_user-group_other.png (100%) rename packages/neon_framework/packages/neon_rich_text/test/{ => rich_objects}/goldens/rich_text_object_mention_user_highlight.png (100%) rename packages/neon_framework/packages/neon_rich_text/test/{ => rich_objects}/goldens/rich_text_object_mention_user_other.png (100%) create mode 100644 packages/neon_framework/packages/neon_rich_text/test/rich_objects/mention_test.dart create mode 100644 packages/neon_framework/packages/neon_rich_text/test/rich_objects/rich_objects_test.dart diff --git a/packages/neon_framework/packages/neon_rich_text/test/rich_objects/deck_card_test.dart b/packages/neon_framework/packages/neon_rich_text/test/rich_objects/deck_card_test.dart new file mode 100644 index 00000000000..fbd8d5bf54f --- /dev/null +++ b/packages/neon_framework/packages/neon_rich_text/test/rich_objects/deck_card_test.dart @@ -0,0 +1,59 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:neon_framework/models.dart'; +import 'package:neon_framework/testing.dart'; +import 'package:neon_rich_text/neon_rich_text.dart'; +import 'package:nextcloud/core.dart' as core; +import 'package:provider/provider.dart'; +import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; + +void main() { + late MockUrlLauncher urlLauncher; + late Account account; + + setUpAll(() { + FakeNeonStorage.setup(); + + registerFallbackValue(const LaunchOptions()); + + urlLauncher = MockUrlLauncher(); + // ignore: discarded_futures + when(() => urlLauncher.launchUrl(any(), any())).thenAnswer((_) async => true); + + UrlLauncherPlatform.instance = urlLauncher; + }); + + setUp(() { + account = MockAccount(); + }); + + testWidgets('Deck card', (tester) async { + await tester.pumpWidgetWithAccessibility( + TestApp( + providers: [ + Provider.value(value: account), + ], + child: NeonRichObjectDeckCard( + parameter: core.RichObjectParameter( + (b) => b + ..type = core.RichObjectParameter_Type.deckCard + ..id = '' + ..name = 'name' + ..boardname = 'boardname' + ..stackname = 'stackname' + ..link = '/link', + ), + ), + ), + ); + expect(find.text('name'), findsOne); + expect(find.text('boardname: stackname'), findsOne); + await expectLater( + find.byType(NeonRichObjectDeckCard), + matchesGoldenFile('goldens/rich_text_object_deck_card.png'), + ); + + await tester.tap(find.byType(NeonRichObjectDeckCard)); + verify(() => urlLauncher.launchUrl('https://cloud.example.com:8443/link', any())).called(1); + }); +} diff --git a/packages/neon_framework/packages/neon_rich_text/test/rich_objects/fallback_test.dart b/packages/neon_framework/packages/neon_rich_text/test/rich_objects/fallback_test.dart new file mode 100644 index 00000000000..bcf7b2bacc8 --- /dev/null +++ b/packages/neon_framework/packages/neon_rich_text/test/rich_objects/fallback_test.dart @@ -0,0 +1,103 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:neon_framework/models.dart'; +import 'package:neon_framework/testing.dart'; +import 'package:neon_framework/widgets.dart'; +import 'package:neon_rich_text/neon_rich_text.dart'; +import 'package:nextcloud/core.dart' as core; +import 'package:provider/provider.dart'; +import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; + +void main() { + late MockUrlLauncher urlLauncher; + late Account account; + + setUpAll(() { + FakeNeonStorage.setup(); + + registerFallbackValue(const LaunchOptions()); + + urlLauncher = MockUrlLauncher(); + // ignore: discarded_futures + when(() => urlLauncher.launchUrl(any(), any())).thenAnswer((_) async => true); + + UrlLauncherPlatform.instance = urlLauncher; + }); + + setUp(() { + account = MockAccount(); + }); + + group('Fallback', () { + testWidgets('Opens link', (tester) async { + await tester.pumpWidgetWithAccessibility( + TestApp( + providers: [ + Provider.value(value: account), + ], + child: NeonRichObjectFallback( + parameter: core.RichObjectParameter( + (b) => b + ..type = core.RichObjectParameter_Type.calendarEvent + ..id = '' + ..name = 'name' + ..link = '/link', + ), + textStyle: null, + ), + ), + ); + + await tester.tap(find.byType(NeonRichObjectFallback)); + verify(() => urlLauncher.launchUrl('https://cloud.example.com:8443/link', any())).called(1); + }); + + testWidgets('Without icon', (tester) async { + await tester.pumpWidgetWithAccessibility( + TestApp( + child: NeonRichObjectFallback( + parameter: core.RichObjectParameter( + (b) => b + ..type = core.RichObjectParameter_Type.addressbook + ..id = '' + ..name = 'name', + ), + textStyle: null, + ), + ), + ); + expect(find.byType(NeonUriImage), findsNothing); + expect(find.text('name'), findsOne); + await expectLater( + find.byType(NeonRichObjectFallback), + matchesGoldenFile('goldens/rich_text_object_fallback_without_icon.png'), + ); + }); + + testWidgets('With icon', (tester) async { + await tester.pumpWidgetWithAccessibility( + TestApp( + providers: [ + Provider.value(value: account), + ], + child: NeonRichObjectFallback( + parameter: core.RichObjectParameter( + (b) => b + ..type = core.RichObjectParameter_Type.addressbook + ..id = '' + ..name = 'name' + ..iconUrl = '', + ), + textStyle: null, + ), + ), + ); + expect(find.byType(NeonUriImage), findsOne); + expect(find.text('name'), findsOne); + await expectLater( + find.byType(NeonRichObjectFallback), + matchesGoldenFile('goldens/rich_text_object_fallback_with_icon.png'), + ); + }); + }); +} diff --git a/packages/neon_framework/packages/neon_rich_text/test/rich_objects/file_test.dart b/packages/neon_framework/packages/neon_rich_text/test/rich_objects/file_test.dart new file mode 100644 index 00000000000..d793adf6458 --- /dev/null +++ b/packages/neon_framework/packages/neon_rich_text/test/rich_objects/file_test.dart @@ -0,0 +1,253 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:neon_framework/models.dart'; +import 'package:neon_framework/testing.dart'; +import 'package:neon_framework/widgets.dart'; +import 'package:neon_rich_text/neon_rich_text.dart'; +import 'package:nextcloud/core.dart' as core; +import 'package:provider/provider.dart'; +import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; + +const validBlurHash = 'LEHLk~WB2yk8pyo0adR*.7kCMdnj'; + +void main() { + late MockUrlLauncher urlLauncher; + late Account account; + + setUpAll(() { + FakeNeonStorage.setup(); + + registerFallbackValue(const LaunchOptions()); + + urlLauncher = MockUrlLauncher(); + // ignore: discarded_futures + when(() => urlLauncher.launchUrl(any(), any())).thenAnswer((_) async => true); + + UrlLauncherPlatform.instance = urlLauncher; + }); + + setUp(() { + account = MockAccount(); + }); + + group('File', () { + const pixelRatio = 3; + const maxWidth = 800; + const maxHeight = 600 ~/ 2; + + testWidgets('Opens link', (tester) async { + await tester.pumpWidgetWithAccessibility( + TestApp( + providers: [ + Provider.value(value: account), + ], + child: NeonRichObjectFile( + parameter: core.RichObjectParameter( + (b) => b + ..type = core.RichObjectParameter_Type.file + ..id = '0' + ..name = 'name' + ..previewAvailable = 'no' + ..path = '' + ..link = '/link', + ), + textStyle: null, + ), + ), + ); + + await tester.tap(find.byType(NeonRichObjectFile)); + verify(() => urlLauncher.launchUrl('https://cloud.example.com:8443/link', any())).called(1); + }); + + testWidgets('With blurhash', (tester) async { + await tester.pumpWidgetWithAccessibility( + TestApp( + providers: [ + Provider.value(value: account), + ], + child: NeonRichObjectFile( + parameter: core.RichObjectParameter( + (b) => b + ..type = core.RichObjectParameter_Type.file + ..id = '0' + ..name = 'name' + ..previewAvailable = 'no' + ..path = '' + ..blurhash = validBlurHash, + ), + textStyle: null, + ), + ), + ); + + expect( + find.byWidgetPredicate( + (widget) => widget is NeonApiImage && widget.blurHash == validBlurHash, + ), + findsOne, + ); + }); + + testWidgets('Without preview', (tester) async { + await tester.pumpWidgetWithAccessibility( + TestApp( + providers: [ + Provider.value(value: account), + ], + child: NeonRichObjectFile( + parameter: core.RichObjectParameter( + (b) => b + ..type = core.RichObjectParameter_Type.file + ..id = '0' + ..name = 'name' + ..previewAvailable = 'no' + ..path = 'path', + ), + textStyle: null, + ), + ), + ); + + expect(find.byTooltip('name'), findsNothing); + expect(find.text('name'), findsOne); + }); + + testWidgets('Without dimensions', (tester) async { + await tester.pumpWidgetWithAccessibility( + TestApp( + providers: [ + Provider.value(value: account), + ], + child: NeonRichObjectFile( + parameter: core.RichObjectParameter( + (b) => b + ..type = core.RichObjectParameter_Type.file + ..id = '0' + ..name = 'name' + ..previewAvailable = 'yes' + ..path = 'path', + ), + textStyle: null, + ), + ), + ); + + final expectedConstraints = BoxConstraints( + minHeight: 100, + maxHeight: maxHeight.toDouble(), + minWidth: 100, + maxWidth: maxWidth.toDouble(), + ); + expect( + find.byWidgetPredicate((widget) => widget is ConstrainedBox && widget.constraints == expectedConstraints), + findsOne, + ); + expect(find.byTooltip('name'), findsOne); + }); + + testWidgets('With dimensions', (tester) async { + const width = 900; + const height = 300; + + await tester.pumpWidgetWithAccessibility( + TestApp( + providers: [ + Provider.value(value: account), + ], + child: NeonRichObjectFile( + parameter: core.RichObjectParameter( + (b) => b + ..type = core.RichObjectParameter_Type.file + ..id = '0' + ..name = 'name' + ..previewAvailable = 'yes' + ..path = 'path' + ..width = width.toString() + ..height = height.toString(), + ), + textStyle: null, + ), + ), + ); + + final expectedConstraints = BoxConstraints.tight(const Size(width / pixelRatio, height / pixelRatio)); + expect( + find.byWidgetPredicate((widget) => widget is ConstrainedBox && widget.constraints == expectedConstraints), + findsOne, + ); + expect(find.byTooltip('name'), findsOne); + }); + + testWidgets('With dimensions too big', (tester) async { + const widthFactor = 2; // Make it too big + const heightFactor = 4; // Make this even bigger + + await tester.pumpWidgetWithAccessibility( + TestApp( + providers: [ + Provider.value(value: account), + ], + child: NeonRichObjectFile( + parameter: core.RichObjectParameter( + (b) => b + ..type = core.RichObjectParameter_Type.file + ..id = '0' + ..name = 'name' + ..previewAvailable = 'yes' + ..path = 'path' + ..width = ((maxWidth * widthFactor) * pixelRatio).toString() + ..height = ((maxHeight * heightFactor) * pixelRatio).toString(), + ), + textStyle: null, + ), + ), + ); + + final size = Size( + widthFactor * maxWidth / heightFactor, + maxHeight.toDouble(), + ); + final expectedConstraints = BoxConstraints.tight(size); + expect( + find.byWidgetPredicate((widget) => widget is ConstrainedBox && widget.constraints == expectedConstraints), + findsOne, + ); + expect(find.byTooltip('name'), findsOne); + }); + + testWidgets('Full image for animated GIF', (tester) async { + await tester.pumpWidgetWithAccessibility( + TestApp( + providers: [ + Provider.value(value: account), + ], + child: NeonRichObjectFile( + parameter: core.RichObjectParameter( + (b) => b + ..type = core.RichObjectParameter_Type.file + ..id = '0' + ..name = 'name' + ..previewAvailable = 'yes' + ..path = 'path' + ..mimetype = 'image/gif' + ..blurhash = validBlurHash, + ), + textStyle: null, + ), + ), + ); + + expect( + find.byWidgetPredicate( + (widget) => + widget is NeonUriImage && + widget.uri.toString() == 'https://cloud.example.com:8443/nextcloud/remote.php/dav/files/username/path' && + widget.blurHash == validBlurHash, + ), + findsOne, + ); + }); + }); +} diff --git a/packages/neon_framework/packages/neon_rich_text/test/goldens/rich_text_object_deck_card.png b/packages/neon_framework/packages/neon_rich_text/test/rich_objects/goldens/rich_text_object_deck_card.png similarity index 100% rename from packages/neon_framework/packages/neon_rich_text/test/goldens/rich_text_object_deck_card.png rename to packages/neon_framework/packages/neon_rich_text/test/rich_objects/goldens/rich_text_object_deck_card.png diff --git a/packages/neon_framework/packages/neon_rich_text/test/goldens/rich_text_object_fallback_with_icon.png b/packages/neon_framework/packages/neon_rich_text/test/rich_objects/goldens/rich_text_object_fallback_with_icon.png similarity index 100% rename from packages/neon_framework/packages/neon_rich_text/test/goldens/rich_text_object_fallback_with_icon.png rename to packages/neon_framework/packages/neon_rich_text/test/rich_objects/goldens/rich_text_object_fallback_with_icon.png diff --git a/packages/neon_framework/packages/neon_rich_text/test/goldens/rich_text_object_fallback_without_icon.png b/packages/neon_framework/packages/neon_rich_text/test/rich_objects/goldens/rich_text_object_fallback_without_icon.png similarity index 100% rename from packages/neon_framework/packages/neon_rich_text/test/goldens/rich_text_object_fallback_without_icon.png rename to packages/neon_framework/packages/neon_rich_text/test/rich_objects/goldens/rich_text_object_fallback_without_icon.png diff --git a/packages/neon_framework/packages/neon_rich_text/test/goldens/rich_text_object_mention_call.png b/packages/neon_framework/packages/neon_rich_text/test/rich_objects/goldens/rich_text_object_mention_call.png similarity index 100% rename from packages/neon_framework/packages/neon_rich_text/test/goldens/rich_text_object_mention_call.png rename to packages/neon_framework/packages/neon_rich_text/test/rich_objects/goldens/rich_text_object_mention_call.png diff --git a/packages/neon_framework/packages/neon_rich_text/test/goldens/rich_text_object_mention_guest.png b/packages/neon_framework/packages/neon_rich_text/test/rich_objects/goldens/rich_text_object_mention_guest.png similarity index 100% rename from packages/neon_framework/packages/neon_rich_text/test/goldens/rich_text_object_mention_guest.png rename to packages/neon_framework/packages/neon_rich_text/test/rich_objects/goldens/rich_text_object_mention_guest.png diff --git a/packages/neon_framework/packages/neon_rich_text/test/goldens/rich_text_object_mention_user-group_highlight.png b/packages/neon_framework/packages/neon_rich_text/test/rich_objects/goldens/rich_text_object_mention_user-group_highlight.png similarity index 100% rename from packages/neon_framework/packages/neon_rich_text/test/goldens/rich_text_object_mention_user-group_highlight.png rename to packages/neon_framework/packages/neon_rich_text/test/rich_objects/goldens/rich_text_object_mention_user-group_highlight.png diff --git a/packages/neon_framework/packages/neon_rich_text/test/goldens/rich_text_object_mention_user-group_other.png b/packages/neon_framework/packages/neon_rich_text/test/rich_objects/goldens/rich_text_object_mention_user-group_other.png similarity index 100% rename from packages/neon_framework/packages/neon_rich_text/test/goldens/rich_text_object_mention_user-group_other.png rename to packages/neon_framework/packages/neon_rich_text/test/rich_objects/goldens/rich_text_object_mention_user-group_other.png diff --git a/packages/neon_framework/packages/neon_rich_text/test/goldens/rich_text_object_mention_user_highlight.png b/packages/neon_framework/packages/neon_rich_text/test/rich_objects/goldens/rich_text_object_mention_user_highlight.png similarity index 100% rename from packages/neon_framework/packages/neon_rich_text/test/goldens/rich_text_object_mention_user_highlight.png rename to packages/neon_framework/packages/neon_rich_text/test/rich_objects/goldens/rich_text_object_mention_user_highlight.png diff --git a/packages/neon_framework/packages/neon_rich_text/test/goldens/rich_text_object_mention_user_other.png b/packages/neon_framework/packages/neon_rich_text/test/rich_objects/goldens/rich_text_object_mention_user_other.png similarity index 100% rename from packages/neon_framework/packages/neon_rich_text/test/goldens/rich_text_object_mention_user_other.png rename to packages/neon_framework/packages/neon_rich_text/test/rich_objects/goldens/rich_text_object_mention_user_other.png diff --git a/packages/neon_framework/packages/neon_rich_text/test/rich_objects/mention_test.dart b/packages/neon_framework/packages/neon_rich_text/test/rich_objects/mention_test.dart new file mode 100644 index 00000000000..8dab2fd598e --- /dev/null +++ b/packages/neon_framework/packages/neon_rich_text/test/rich_objects/mention_test.dart @@ -0,0 +1,181 @@ +import 'package:built_collection/built_collection.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:neon_framework/blocs.dart'; +import 'package:neon_framework/models.dart'; +import 'package:neon_framework/testing.dart'; +import 'package:neon_framework/theme.dart'; +import 'package:neon_framework/utils.dart'; +import 'package:neon_framework/widgets.dart'; +import 'package:neon_rich_text/neon_rich_text.dart'; +import 'package:nextcloud/core.dart' as core; +import 'package:provider/provider.dart'; +import 'package:rxdart/rxdart.dart'; + +void main() { + late Account account; + + setUpAll(() { + FakeNeonStorage.setup(); + }); + + setUp(() { + account = MockAccount(); + }); + + group('Mention', () { + group('user', () { + testWidgets('Self', (tester) async { + await tester.pumpWidgetWithAccessibility( + TestApp( + providers: [ + Provider.value(value: account), + ], + child: NeonRichObjectMention( + parameter: core.RichObjectParameter( + (b) => b + ..type = core.RichObjectParameter_Type.user + ..id = 'username' + ..name = 'name', + ), + textStyle: null, + ), + ), + ); + expect(find.byType(NeonUserAvatar), findsOne); + expect(find.text('name'), findsOne); + await expectLater( + find.byType(NeonRichObjectMention), + matchesGoldenFile('goldens/rich_text_object_mention_user_highlight.png'), + ); + }); + + testWidgets('Other', (tester) async { + await tester.pumpWidgetWithAccessibility( + TestApp( + providers: [ + Provider.value(value: account), + ], + child: NeonRichObjectMention( + parameter: core.RichObjectParameter( + (b) => b + ..type = core.RichObjectParameter_Type.user + ..id = 'other' + ..name = 'name', + ), + textStyle: null, + ), + ), + ); + expect(find.byType(NeonUserAvatar), findsOne); + expect(find.text('name'), findsOne); + await expectLater( + find.byType(NeonRichObjectMention), + matchesGoldenFile('goldens/rich_text_object_mention_user_other.png'), + ); + }); + }); + + testWidgets('call', (tester) async { + await tester.pumpWidgetWithAccessibility( + TestApp( + providers: [ + Provider.value(value: account), + ], + child: NeonRichObjectMention( + parameter: core.RichObjectParameter( + (b) => b + ..type = core.RichObjectParameter_Type.call + ..id = '' + ..name = 'name' + ..iconUrl = '', + ), + textStyle: null, + ), + ), + ); + expect(find.byType(NeonUriImage), findsOne); + expect(find.text('name'), findsOne); + await expectLater( + find.byType(NeonRichObjectMention), + matchesGoldenFile('goldens/rich_text_object_mention_call.png'), + ); + }); + + testWidgets('guest', (tester) async { + await tester.pumpWidgetWithAccessibility( + TestApp( + child: NeonRichObjectMention( + parameter: core.RichObjectParameter( + (b) => b + ..type = core.RichObjectParameter_Type.guest + ..id = '' + ..name = 'name', + ), + textStyle: null, + ), + ), + ); + expect(find.byIcon(AdaptiveIcons.person), findsOne); + expect(find.text('name'), findsOne); + await expectLater( + find.byType(NeonRichObjectMention), + matchesGoldenFile('goldens/rich_text_object_mention_guest.png'), + ); + }); + + testWidgets('user-group', (tester) async { + final userDetails = MockUserDetails(); + when(() => userDetails.groups).thenReturn(BuiltList(['group'])); + + final userDetailsBloc = MockUserDetailsBloc(); + when(() => userDetailsBloc.userDetails).thenAnswer((_) => BehaviorSubject.seeded(Result.success(userDetails))); + + await tester.pumpWidgetWithAccessibility( + TestApp( + providers: [ + NeonProvider.value(value: userDetailsBloc), + ], + child: NeonRichObjectMention( + parameter: core.RichObjectParameter( + (b) => b + ..type = core.RichObjectParameter_Type.userGroup + ..id = 'group' + ..name = 'name', + ), + textStyle: null, + ), + ), + ); + expect(find.byIcon(AdaptiveIcons.group), findsOne); + expect(find.text('name'), findsOne); + await expectLater( + find.byType(NeonRichObjectMention), + matchesGoldenFile('goldens/rich_text_object_mention_user-group_highlight.png'), + ); + + await tester.pumpWidgetWithAccessibility( + TestApp( + providers: [ + NeonProvider.value(value: userDetailsBloc), + ], + child: NeonRichObjectMention( + parameter: core.RichObjectParameter( + (b) => b + ..type = core.RichObjectParameter_Type.userGroup + ..id = 'other' + ..name = 'name', + ), + textStyle: null, + ), + ), + ); + expect(find.byIcon(AdaptiveIcons.group), findsOne); + expect(find.text('name'), findsOne); + await expectLater( + find.byType(NeonRichObjectMention), + matchesGoldenFile('goldens/rich_text_object_mention_user-group_other.png'), + ); + }); + }); +} diff --git a/packages/neon_framework/packages/neon_rich_text/test/rich_objects/rich_objects_test.dart b/packages/neon_framework/packages/neon_rich_text/test/rich_objects/rich_objects_test.dart new file mode 100644 index 00000000000..bd1a4beebb3 --- /dev/null +++ b/packages/neon_framework/packages/neon_rich_text/test/rich_objects/rich_objects_test.dart @@ -0,0 +1,143 @@ +import 'package:built_collection/built_collection.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:neon_framework/blocs.dart'; +import 'package:neon_framework/models.dart'; +import 'package:neon_framework/testing.dart'; +import 'package:neon_framework/utils.dart'; +import 'package:neon_rich_text/neon_rich_text.dart'; +import 'package:neon_rich_text/src/rich_objects/rich_objects.dart'; +import 'package:nextcloud/core.dart' as core; +import 'package:provider/provider.dart'; +import 'package:rxdart/rxdart.dart'; + +void main() { + setUpAll(() { + FakeNeonStorage.setup(); + }); + + group('buildRichObjectParameter', () { + for (final isPreview in [true, false]) { + group(isPreview ? 'As preview' : 'Complete', () { + group('Mention', () { + for (final type in [ + core.RichObjectParameter_Type.user, + core.RichObjectParameter_Type.call, + core.RichObjectParameter_Type.guest, + core.RichObjectParameter_Type.userGroup, + ]) { + testWidgets(type.value, (tester) async { + final userDetails = MockUserDetails(); + when(() => userDetails.groups).thenReturn(BuiltList()); + + final userDetailsBloc = MockUserDetailsBloc(); + when(() => userDetailsBloc.userDetails) + .thenAnswer((_) => BehaviorSubject.seeded(Result.success(userDetails))); + + final account = MockAccount(); + + await tester.pumpWidgetWithAccessibility( + TestApp( + providers: [ + Provider.value(value: account), + NeonProvider.value(value: userDetailsBloc), + ], + child: RichText( + text: buildRichObjectParameter( + parameter: core.RichObjectParameter( + (b) => b + ..type = type + ..id = '' + ..name = 'name' + ..iconUrl = '', + ), + textStyle: null, + isPreview: isPreview, + ), + ), + ), + ); + + expect(find.byType(NeonRichObjectMention), isPreview ? findsNothing : findsOne); + expect(find.text('name', findRichText: true), findsOne); + }); + } + }); + + testWidgets('File', (tester) async { + final account = MockAccount(); + + await tester.pumpWidgetWithAccessibility( + TestApp( + providers: [ + Provider.value(value: account), + ], + child: RichText( + text: buildRichObjectParameter( + parameter: core.RichObjectParameter( + (b) => b + ..type = core.RichObjectParameter_Type.file + ..id = '0' + ..name = 'name', + ), + textStyle: null, + isPreview: isPreview, + ), + ), + ), + ); + + expect(find.byType(NeonRichObjectFile), isPreview ? findsNothing : findsOne); + expect(find.text('name', findRichText: true), findsOne); + }); + + testWidgets('Deck card', (tester) async { + await tester.pumpWidgetWithAccessibility( + TestApp( + child: RichText( + text: buildRichObjectParameter( + parameter: core.RichObjectParameter( + (b) => b + ..type = core.RichObjectParameter_Type.deckCard + ..id = '' + ..name = 'name' + ..boardname = 'boardname' + ..stackname = 'stackname', + ), + textStyle: null, + isPreview: isPreview, + ), + ), + ), + ); + + expect(find.byType(NeonRichObjectDeckCard), isPreview ? findsNothing : findsOne); + expect(find.text('name', findRichText: true), findsOne); + }); + + testWidgets('Fallback', (tester) async { + await tester.pumpWidgetWithAccessibility( + TestApp( + child: RichText( + text: buildRichObjectParameter( + parameter: core.RichObjectParameter( + (b) => b + ..type = core.RichObjectParameter_Type.addressbook + ..id = '' + ..name = 'name', + ), + textStyle: null, + isPreview: isPreview, + ), + ), + ), + ); + + expect(find.byType(NeonRichObjectFallback), isPreview ? findsNothing : findsOne); + expect(find.text('name', findRichText: true), findsOne); + }); + }); + } + }); +} diff --git a/packages/neon_framework/packages/neon_rich_text/test/rich_text_test.dart b/packages/neon_framework/packages/neon_rich_text/test/rich_text_test.dart index b5d424107b1..38bb8d85eeb 100644 --- a/packages/neon_framework/packages/neon_rich_text/test/rich_text_test.dart +++ b/packages/neon_framework/packages/neon_rich_text/test/rich_text_test.dart @@ -4,648 +4,14 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; -import 'package:neon_framework/blocs.dart'; -import 'package:neon_framework/models.dart'; -import 'package:neon_framework/testing.dart'; -import 'package:neon_framework/theme.dart'; -import 'package:neon_framework/utils.dart'; -import 'package:neon_framework/widgets.dart'; import 'package:neon_rich_text/neon_rich_text.dart'; -import 'package:neon_rich_text/src/rich_objects/rich_objects.dart'; import 'package:nextcloud/core.dart' as core; -import 'package:provider/provider.dart'; -import 'package:rxdart/rxdart.dart'; -import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; - -const validBlurHash = 'LEHLk~WB2yk8pyo0adR*.7kCMdnj'; class MockOnReferenceClickedCallback extends Mock { void call(String reference); } void main() { - late MockUrlLauncher urlLauncher; - late Account account; - - setUpAll(() { - FakeNeonStorage.setup(); - - registerFallbackValue(const LaunchOptions()); - - urlLauncher = MockUrlLauncher(); - // ignore: discarded_futures - when(() => urlLauncher.launchUrl(any(), any())).thenAnswer((_) async => true); - - UrlLauncherPlatform.instance = urlLauncher; - }); - - setUp(() { - account = MockAccount(); - }); - - testWidgets('Deck card', (tester) async { - await tester.pumpWidgetWithAccessibility( - TestApp( - providers: [ - Provider.value(value: account), - ], - child: NeonRichObjectDeckCard( - parameter: core.RichObjectParameter( - (b) => b - ..type = core.RichObjectParameter_Type.deckCard - ..id = '' - ..name = 'name' - ..boardname = 'boardname' - ..stackname = 'stackname' - ..link = '/link', - ), - ), - ), - ); - expect(find.text('name'), findsOne); - expect(find.text('boardname: stackname'), findsOne); - await expectLater( - find.byType(NeonRichObjectDeckCard), - matchesGoldenFile('goldens/rich_text_object_deck_card.png'), - ); - - await tester.tap(find.byType(NeonRichObjectDeckCard)); - verify(() => urlLauncher.launchUrl('https://cloud.example.com:8443/link', any())).called(1); - }); - - group('Mention', () { - group('user', () { - testWidgets('Self', (tester) async { - await tester.pumpWidgetWithAccessibility( - TestApp( - providers: [ - Provider.value(value: account), - ], - child: NeonRichObjectMention( - parameter: core.RichObjectParameter( - (b) => b - ..type = core.RichObjectParameter_Type.user - ..id = 'username' - ..name = 'name', - ), - textStyle: null, - ), - ), - ); - expect(find.byType(NeonUserAvatar), findsOne); - expect(find.text('name'), findsOne); - await expectLater( - find.byType(NeonRichObjectMention), - matchesGoldenFile('goldens/rich_text_object_mention_user_highlight.png'), - ); - }); - - testWidgets('Other', (tester) async { - await tester.pumpWidgetWithAccessibility( - TestApp( - providers: [ - Provider.value(value: account), - ], - child: NeonRichObjectMention( - parameter: core.RichObjectParameter( - (b) => b - ..type = core.RichObjectParameter_Type.user - ..id = 'other' - ..name = 'name', - ), - textStyle: null, - ), - ), - ); - expect(find.byType(NeonUserAvatar), findsOne); - expect(find.text('name'), findsOne); - await expectLater( - find.byType(NeonRichObjectMention), - matchesGoldenFile('goldens/rich_text_object_mention_user_other.png'), - ); - }); - }); - - testWidgets('call', (tester) async { - await tester.pumpWidgetWithAccessibility( - TestApp( - providers: [ - Provider.value(value: account), - ], - child: NeonRichObjectMention( - parameter: core.RichObjectParameter( - (b) => b - ..type = core.RichObjectParameter_Type.call - ..id = '' - ..name = 'name' - ..iconUrl = '', - ), - textStyle: null, - ), - ), - ); - expect(find.byType(NeonUriImage), findsOne); - expect(find.text('name'), findsOne); - await expectLater( - find.byType(NeonRichObjectMention), - matchesGoldenFile('goldens/rich_text_object_mention_call.png'), - ); - }); - - testWidgets('guest', (tester) async { - await tester.pumpWidgetWithAccessibility( - TestApp( - child: NeonRichObjectMention( - parameter: core.RichObjectParameter( - (b) => b - ..type = core.RichObjectParameter_Type.guest - ..id = '' - ..name = 'name', - ), - textStyle: null, - ), - ), - ); - expect(find.byIcon(AdaptiveIcons.person), findsOne); - expect(find.text('name'), findsOne); - await expectLater( - find.byType(NeonRichObjectMention), - matchesGoldenFile('goldens/rich_text_object_mention_guest.png'), - ); - }); - - testWidgets('user-group', (tester) async { - final userDetails = MockUserDetails(); - when(() => userDetails.groups).thenReturn(BuiltList(['group'])); - - final userDetailsBloc = MockUserDetailsBloc(); - when(() => userDetailsBloc.userDetails).thenAnswer((_) => BehaviorSubject.seeded(Result.success(userDetails))); - - await tester.pumpWidgetWithAccessibility( - TestApp( - providers: [ - NeonProvider.value(value: userDetailsBloc), - ], - child: NeonRichObjectMention( - parameter: core.RichObjectParameter( - (b) => b - ..type = core.RichObjectParameter_Type.userGroup - ..id = 'group' - ..name = 'name', - ), - textStyle: null, - ), - ), - ); - expect(find.byIcon(AdaptiveIcons.group), findsOne); - expect(find.text('name'), findsOne); - await expectLater( - find.byType(NeonRichObjectMention), - matchesGoldenFile('goldens/rich_text_object_mention_user-group_highlight.png'), - ); - - await tester.pumpWidgetWithAccessibility( - TestApp( - providers: [ - NeonProvider.value(value: userDetailsBloc), - ], - child: NeonRichObjectMention( - parameter: core.RichObjectParameter( - (b) => b - ..type = core.RichObjectParameter_Type.userGroup - ..id = 'other' - ..name = 'name', - ), - textStyle: null, - ), - ), - ); - expect(find.byIcon(AdaptiveIcons.group), findsOne); - expect(find.text('name'), findsOne); - await expectLater( - find.byType(NeonRichObjectMention), - matchesGoldenFile('goldens/rich_text_object_mention_user-group_other.png'), - ); - }); - }); - - group('File', () { - const pixelRatio = 3; - const maxWidth = 800; - const maxHeight = 600 ~/ 2; - - testWidgets('Opens link', (tester) async { - await tester.pumpWidgetWithAccessibility( - TestApp( - providers: [ - Provider.value(value: account), - ], - child: NeonRichObjectFile( - parameter: core.RichObjectParameter( - (b) => b - ..type = core.RichObjectParameter_Type.file - ..id = '0' - ..name = 'name' - ..previewAvailable = 'no' - ..path = '' - ..link = '/link', - ), - textStyle: null, - ), - ), - ); - - await tester.tap(find.byType(NeonRichObjectFile)); - verify(() => urlLauncher.launchUrl('https://cloud.example.com:8443/link', any())).called(1); - }); - - testWidgets('With blurhash', (tester) async { - await tester.pumpWidgetWithAccessibility( - TestApp( - providers: [ - Provider.value(value: account), - ], - child: NeonRichObjectFile( - parameter: core.RichObjectParameter( - (b) => b - ..type = core.RichObjectParameter_Type.file - ..id = '0' - ..name = 'name' - ..previewAvailable = 'no' - ..path = '' - ..blurhash = validBlurHash, - ), - textStyle: null, - ), - ), - ); - - expect( - find.byWidgetPredicate( - (widget) => widget is NeonApiImage && widget.blurHash == validBlurHash, - ), - findsOne, - ); - }); - - testWidgets('Without preview', (tester) async { - await tester.pumpWidgetWithAccessibility( - TestApp( - providers: [ - Provider.value(value: account), - ], - child: NeonRichObjectFile( - parameter: core.RichObjectParameter( - (b) => b - ..type = core.RichObjectParameter_Type.file - ..id = '0' - ..name = 'name' - ..previewAvailable = 'no' - ..path = 'path', - ), - textStyle: null, - ), - ), - ); - - expect(find.byTooltip('name'), findsNothing); - expect(find.text('name'), findsOne); - }); - - testWidgets('Without dimensions', (tester) async { - await tester.pumpWidgetWithAccessibility( - TestApp( - providers: [ - Provider.value(value: account), - ], - child: NeonRichObjectFile( - parameter: core.RichObjectParameter( - (b) => b - ..type = core.RichObjectParameter_Type.file - ..id = '0' - ..name = 'name' - ..previewAvailable = 'yes' - ..path = 'path', - ), - textStyle: null, - ), - ), - ); - - final expectedConstraints = BoxConstraints( - minHeight: 100, - maxHeight: maxHeight.toDouble(), - minWidth: 100, - maxWidth: maxWidth.toDouble(), - ); - expect( - find.byWidgetPredicate((widget) => widget is ConstrainedBox && widget.constraints == expectedConstraints), - findsOne, - ); - expect(find.byTooltip('name'), findsOne); - }); - - testWidgets('With dimensions', (tester) async { - const width = 900; - const height = 300; - - await tester.pumpWidgetWithAccessibility( - TestApp( - providers: [ - Provider.value(value: account), - ], - child: NeonRichObjectFile( - parameter: core.RichObjectParameter( - (b) => b - ..type = core.RichObjectParameter_Type.file - ..id = '0' - ..name = 'name' - ..previewAvailable = 'yes' - ..path = 'path' - ..width = width.toString() - ..height = height.toString(), - ), - textStyle: null, - ), - ), - ); - - final expectedConstraints = BoxConstraints.tight(const Size(width / pixelRatio, height / pixelRatio)); - expect( - find.byWidgetPredicate((widget) => widget is ConstrainedBox && widget.constraints == expectedConstraints), - findsOne, - ); - expect(find.byTooltip('name'), findsOne); - }); - - testWidgets('With dimensions too big', (tester) async { - const widthFactor = 2; // Make it too big - const heightFactor = 4; // Make this even bigger - - await tester.pumpWidgetWithAccessibility( - TestApp( - providers: [ - Provider.value(value: account), - ], - child: NeonRichObjectFile( - parameter: core.RichObjectParameter( - (b) => b - ..type = core.RichObjectParameter_Type.file - ..id = '0' - ..name = 'name' - ..previewAvailable = 'yes' - ..path = 'path' - ..width = ((maxWidth * widthFactor) * pixelRatio).toString() - ..height = ((maxHeight * heightFactor) * pixelRatio).toString(), - ), - textStyle: null, - ), - ), - ); - - final size = Size( - widthFactor * maxWidth / heightFactor, - maxHeight.toDouble(), - ); - final expectedConstraints = BoxConstraints.tight(size); - expect( - find.byWidgetPredicate((widget) => widget is ConstrainedBox && widget.constraints == expectedConstraints), - findsOne, - ); - expect(find.byTooltip('name'), findsOne); - }); - - testWidgets('Full image for animated GIF', (tester) async { - await tester.pumpWidgetWithAccessibility( - TestApp( - providers: [ - Provider.value(value: account), - ], - child: NeonRichObjectFile( - parameter: core.RichObjectParameter( - (b) => b - ..type = core.RichObjectParameter_Type.file - ..id = '0' - ..name = 'name' - ..previewAvailable = 'yes' - ..path = 'path' - ..mimetype = 'image/gif' - ..blurhash = validBlurHash, - ), - textStyle: null, - ), - ), - ); - - expect( - find.byWidgetPredicate( - (widget) => - widget is NeonUriImage && - widget.uri.toString() == 'https://cloud.example.com:8443/nextcloud/remote.php/dav/files/username/path' && - widget.blurHash == validBlurHash, - ), - findsOne, - ); - }); - }); - - group('Fallback', () { - testWidgets('Opens link', (tester) async { - await tester.pumpWidgetWithAccessibility( - TestApp( - providers: [ - Provider.value(value: account), - ], - child: NeonRichObjectFallback( - parameter: core.RichObjectParameter( - (b) => b - ..type = core.RichObjectParameter_Type.calendarEvent - ..id = '' - ..name = 'name' - ..link = '/link', - ), - textStyle: null, - ), - ), - ); - - await tester.tap(find.byType(NeonRichObjectFallback)); - verify(() => urlLauncher.launchUrl('https://cloud.example.com:8443/link', any())).called(1); - }); - - testWidgets('Without icon', (tester) async { - await tester.pumpWidgetWithAccessibility( - TestApp( - child: NeonRichObjectFallback( - parameter: core.RichObjectParameter( - (b) => b - ..type = core.RichObjectParameter_Type.addressbook - ..id = '' - ..name = 'name', - ), - textStyle: null, - ), - ), - ); - expect(find.byType(NeonUriImage), findsNothing); - expect(find.text('name'), findsOne); - await expectLater( - find.byType(NeonRichObjectFallback), - matchesGoldenFile('goldens/rich_text_object_fallback_without_icon.png'), - ); - }); - - testWidgets('With icon', (tester) async { - await tester.pumpWidgetWithAccessibility( - TestApp( - providers: [ - Provider.value(value: account), - ], - child: NeonRichObjectFallback( - parameter: core.RichObjectParameter( - (b) => b - ..type = core.RichObjectParameter_Type.addressbook - ..id = '' - ..name = 'name' - ..iconUrl = '', - ), - textStyle: null, - ), - ), - ); - expect(find.byType(NeonUriImage), findsOne); - expect(find.text('name'), findsOne); - await expectLater( - find.byType(NeonRichObjectFallback), - matchesGoldenFile('goldens/rich_text_object_fallback_with_icon.png'), - ); - }); - }); - - group('buildRichObjectParameter', () { - for (final isPreview in [true, false]) { - group(isPreview ? 'As preview' : 'Complete', () { - group('Mention', () { - for (final type in [ - core.RichObjectParameter_Type.user, - core.RichObjectParameter_Type.call, - core.RichObjectParameter_Type.guest, - core.RichObjectParameter_Type.userGroup, - ]) { - testWidgets(type.value, (tester) async { - final userDetails = MockUserDetails(); - when(() => userDetails.groups).thenReturn(BuiltList()); - - final userDetailsBloc = MockUserDetailsBloc(); - when(() => userDetailsBloc.userDetails) - .thenAnswer((_) => BehaviorSubject.seeded(Result.success(userDetails))); - - final account = MockAccount(); - - await tester.pumpWidgetWithAccessibility( - TestApp( - providers: [ - Provider.value(value: account), - NeonProvider.value(value: userDetailsBloc), - ], - child: RichText( - text: buildRichObjectParameter( - parameter: core.RichObjectParameter( - (b) => b - ..type = type - ..id = '' - ..name = 'name' - ..iconUrl = '', - ), - textStyle: null, - isPreview: isPreview, - ), - ), - ), - ); - - expect(find.byType(NeonRichObjectMention), isPreview ? findsNothing : findsOne); - expect(find.text('name', findRichText: true), findsOne); - }); - } - }); - - testWidgets('File', (tester) async { - final account = MockAccount(); - - await tester.pumpWidgetWithAccessibility( - TestApp( - providers: [ - Provider.value(value: account), - ], - child: RichText( - text: buildRichObjectParameter( - parameter: core.RichObjectParameter( - (b) => b - ..type = core.RichObjectParameter_Type.file - ..id = '0' - ..name = 'name', - ), - textStyle: null, - isPreview: isPreview, - ), - ), - ), - ); - - expect(find.byType(NeonRichObjectFile), isPreview ? findsNothing : findsOne); - expect(find.text('name', findRichText: true), findsOne); - }); - - testWidgets('Deck card', (tester) async { - await tester.pumpWidgetWithAccessibility( - TestApp( - child: RichText( - text: buildRichObjectParameter( - parameter: core.RichObjectParameter( - (b) => b - ..type = core.RichObjectParameter_Type.deckCard - ..id = '' - ..name = 'name' - ..boardname = 'boardname' - ..stackname = 'stackname', - ), - textStyle: null, - isPreview: isPreview, - ), - ), - ), - ); - - expect(find.byType(NeonRichObjectDeckCard), isPreview ? findsNothing : findsOne); - expect(find.text('name', findRichText: true), findsOne); - }); - - testWidgets('Fallback', (tester) async { - await tester.pumpWidgetWithAccessibility( - TestApp( - child: RichText( - text: buildRichObjectParameter( - parameter: core.RichObjectParameter( - (b) => b - ..type = core.RichObjectParameter_Type.addressbook - ..id = '' - ..name = 'name', - ), - textStyle: null, - isPreview: isPreview, - ), - ), - ), - ); - - expect(find.byType(NeonRichObjectFallback), isPreview ? findsNothing : findsOne); - expect(find.text('name', findRichText: true), findsOne); - }); - }); - } - }); - group('buildRichTextSpan', () { test('Preview without newlines', () { var span = buildRichTextSpan(