diff --git a/test/features/mailbox_dashboard/presentation/view/mailbox_dashboard_view_widget_test.dart b/test/features/mailbox_dashboard/presentation/view/mailbox_dashboard_view_widget_test.dart index e96daf350..d9f5d2bc9 100644 --- a/test/features/mailbox_dashboard/presentation/view/mailbox_dashboard_view_widget_test.dart +++ b/test/features/mailbox_dashboard/presentation/view/mailbox_dashboard_view_widget_test.dart @@ -17,10 +17,12 @@ import 'package:model/email/presentation_email.dart'; import 'package:model/extensions/email_extension.dart'; import 'package:model/extensions/email_id_extensions.dart'; import 'package:model/extensions/mailbox_extension.dart'; +import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:rxdart/subjects.dart'; import 'package:tmail_ui_user/features/caching/caching_manager.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/send_email_interactor.dart'; import 'package:tmail_ui_user/features/composer/presentation/manager/composer_manager.dart'; +import 'package:tmail_ui_user/features/download/presentation/controllers/download_controller.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/delete_email_permanently_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/delete_multiple_emails_permanently_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/get_restored_deleted_message_interactor.dart'; @@ -41,6 +43,8 @@ import 'package:tmail_ui_user/features/login/domain/usecases/get_oidc_user_info_ import 'package:tmail_ui_user/features/login/domain/usecases/get_stored_oidc_configuration_interactor.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/get_token_oidc_interactor.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/update_account_cache_interactor.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/state/create_default_mailbox_state.dart'; +import 'package:tmail_ui_user/features/mailbox/domain/state/get_all_mailboxes_state.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/clear_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/create_new_default_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/create_new_mailbox_interactor.dart'; @@ -55,7 +59,11 @@ import 'package:tmail_ui_user/features/mailbox/domain/usecases/subaddressing_int import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_multiple_mailbox_interactor.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_controller.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/mailbox_view_web.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_node.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart'; +import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_item_widget.dart'; import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_name_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/spam_report_state.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/get_all_recent_search_latest_interactor.dart'; @@ -69,7 +77,6 @@ import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/save_re import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/store_email_sort_order_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/download_ui_action.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/app_grid_dashboard_controller.dart'; -import 'package:tmail_ui_user/features/download/presentation/controllers/download_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/search_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/spam_report_controller.dart'; @@ -103,6 +110,7 @@ import 'package:tmail_ui_user/features/thread/domain/usecases/search_more_email_ import 'package:tmail_ui_user/features/thread/presentation/thread_controller.dart'; import 'package:tmail_ui_user/features/thread/presentation/thread_view.dart'; import 'package:tmail_ui_user/main/bindings/network/binding_tag.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations_delegate.dart'; import 'package:tmail_ui_user/main/localizations/localization_service.dart'; import 'package:tmail_ui_user/main/utils/email_receive_manager.dart'; @@ -114,6 +122,7 @@ import '../../../../fixtures/account_fixtures.dart'; import '../../../../fixtures/email_fixtures.dart'; import '../../../../fixtures/mailbox_fixtures.dart'; import '../../../../fixtures/session_fixtures.dart'; +import '../../../../fixtures/widget_fixtures.dart'; import 'mailbox_dashboard_view_widget_test.mocks.dart'; mockControllerCallback() => InternalFinalCallback(callback: () {}); @@ -313,7 +322,7 @@ void main() { ); } - group('MailboxDashboardView::WidgetTest::OnWeb', () { + group('MailboxDashboardView', () { setUp(() { Get.testMode = true; @@ -413,7 +422,8 @@ void main() { getAllMailboxInteractor, refreshAllMailboxInteractor ); - mailboxController.onReady(); + Get.put(mailboxController); + // mailboxController.onReady(); threadController = ThreadController( getEmailsInMailboxInteractor, @@ -434,7 +444,7 @@ void main() { mailboxDashboardController.accountId.value = AccountFixtures.aliceAccountId; }); - group('ThreadView::test', () { + group('ThreadView', () { testWidgets( 'WHEN switch from old mailbox to new mailbox\n' 'AND old mailbox and new mailbox both have emails\n' @@ -735,6 +745,292 @@ void main() { }); }); + group('MailboxView', () { + testWidgets( + 'GIVEN AI Needs Action is enabled and session supports AI ' + 'WHEN mailboxes are loaded ' + 'THEN Action Required folder is displayed', + (tester) async { + final currentMailboxList = [ + MailboxFixtures.inboxMailbox.toPresentationMailbox(), + MailboxFixtures.sentMailbox.toPresentationMailbox(), + MailboxFixtures.folder1.toPresentationMailbox(), + MailboxFixtures.mailboxA.toPresentationMailbox(), + MailboxFixtures.mailboxB.toPresentationMailbox(), + MailboxFixtures.mailboxC.toPresentationMailbox(), + MailboxFixtures.mailboxD.toPresentationMailbox(), + ]; + + final defaultTree = MailboxTree( + MailboxNode( + MailboxNode.rootItem(), + childrenItems: [ + MailboxNode( + MailboxFixtures.inboxMailbox.toPresentationMailbox()), + MailboxNode( + MailboxFixtures.sentMailbox.toPresentationMailbox()), + ], + ), + ); + + final personalTree = MailboxTree( + MailboxNode( + MailboxNode.rootItem(), + childrenItems: [ + MailboxNode(MailboxFixtures.folder1.toPresentationMailbox()), + MailboxNode(MailboxFixtures.mailboxA.toPresentationMailbox()), + MailboxNode(MailboxFixtures.mailboxB.toPresentationMailbox()), + MailboxNode(MailboxFixtures.mailboxC.toPresentationMailbox()), + MailboxNode(MailboxFixtures.mailboxD.toPresentationMailbox()), + ], + ), + ); + + final teamTree = MailboxTree(MailboxNode.root()); + final currentSession = SessionFixtures.aliceSessionWithAICapability; + + // Arrange + when( + mailboxDashboardController + .appGridDashboardController.listLinagoraApp, + ).thenReturn(RxList([])); + + when( + createDefaultMailboxInteractor.execute(any, any, any), + ).thenAnswer( + (_) => Stream.value(Right(CreateDefaultMailboxAllSuccess([]))), + ); + + when( + treeBuilder.generateMailboxTreeInUI( + allMailboxes: anyNamed('allMailboxes'), + currentDefaultTree: anyNamed('currentDefaultTree'), + currentPersonalTree: anyNamed('currentPersonalTree'), + currentTeamMailboxTree: anyNamed('currentTeamMailboxTree'), + mailboxIdSelected: anyNamed('mailboxIdSelected'), + mailboxIdExpanded: anyNamed('mailboxIdExpanded'), + ), + ).thenAnswer( + (_) async => ( + allMailboxes: currentMailboxList, + defaultTree: defaultTree, + personalTree: personalTree, + teamMailboxTree: teamTree, + ), + ); + + when(uuid.v1()).thenReturn('dab123456789'); + + mailboxDashboardController.isAINeedsActionSettingEnabled.value = true; + mailboxDashboardController.sessionCurrent = currentSession; + + // Act + await WidgetFixtures.pumpResponsiveWidget( + tester, + WidgetFixtures.makeTestableWidget( + child: MailboxView(), + ), + logicalSize: const Size(1920, 1080), + platform: TargetPlatform.macOS, + ); + + mailboxController.consumeState( + Stream.value( + Right( + GetAllMailboxSuccess( + mailboxList: currentMailboxList, + currentMailboxState: MailboxFixtures.currentState, + ), + ), + ), + ); + + await tester.pump(); + mailboxController.defaultMailboxTree.refresh(); + await tester.pump(); + + // Assert + verify( + treeBuilder.generateMailboxTreeInUI( + allMailboxes: anyNamed('allMailboxes'), + currentDefaultTree: anyNamed('currentDefaultTree'), + currentPersonalTree: anyNamed('currentPersonalTree'), + currentTeamMailboxTree: anyNamed('currentTeamMailboxTree'), + mailboxIdSelected: anyNamed('mailboxIdSelected'), + mailboxIdExpanded: anyNamed('mailboxIdExpanded'), + ), + ).called(1); + + verify( + createDefaultMailboxInteractor.execute(any, any, any), + ).called(1); + + expect(find.byType(MailboxView), findsOneWidget); + expect(find.byType(MailboxItemWidget), findsAtLeastNWidgets(1)); + + expect( + find.byWidgetPredicate( + (widget) => + widget is MailboxItemWidget && + widget.mailboxNode.item.id == + PresentationMailbox.actionRequiredFolder.id, + ), + findsOneWidget, + ); + + expect( + find.text(AppLocalizations().actionRequiredMailboxDisplayName), + findsOneWidget, + ); + + WidgetFixtures.resetResponsive(tester); + }, + ); + + testWidgets( + 'GIVEN AI Needs Action is disabled or session not supports AI ' + 'WHEN mailboxes are loaded ' + 'THEN Action Required folder is not displayed', + (tester) async { + final currentMailboxList = [ + MailboxFixtures.inboxMailbox.toPresentationMailbox(), + MailboxFixtures.sentMailbox.toPresentationMailbox(), + MailboxFixtures.folder1.toPresentationMailbox(), + MailboxFixtures.mailboxA.toPresentationMailbox(), + MailboxFixtures.mailboxB.toPresentationMailbox(), + MailboxFixtures.mailboxC.toPresentationMailbox(), + MailboxFixtures.mailboxD.toPresentationMailbox(), + ]; + + final defaultTree = MailboxTree( + MailboxNode( + MailboxNode.rootItem(), + childrenItems: [ + MailboxNode( + MailboxFixtures.inboxMailbox.toPresentationMailbox()), + MailboxNode( + MailboxFixtures.sentMailbox.toPresentationMailbox()), + ], + ), + ); + + final personalTree = MailboxTree( + MailboxNode( + MailboxNode.rootItem(), + childrenItems: [ + MailboxNode(MailboxFixtures.folder1.toPresentationMailbox()), + MailboxNode(MailboxFixtures.mailboxA.toPresentationMailbox()), + MailboxNode(MailboxFixtures.mailboxB.toPresentationMailbox()), + MailboxNode(MailboxFixtures.mailboxC.toPresentationMailbox()), + MailboxNode(MailboxFixtures.mailboxD.toPresentationMailbox()), + ], + ), + ); + + final teamTree = MailboxTree(MailboxNode.root()); + final currentSession = + SessionFixtures.aliceSessionWithoutAICapability; + + // Arrange + when( + mailboxDashboardController + .appGridDashboardController.listLinagoraApp, + ).thenReturn(RxList([])); + + when( + createDefaultMailboxInteractor.execute(any, any, any), + ).thenAnswer( + (_) => Stream.value(Right(CreateDefaultMailboxAllSuccess([]))), + ); + + when( + treeBuilder.generateMailboxTreeInUI( + allMailboxes: anyNamed('allMailboxes'), + currentDefaultTree: anyNamed('currentDefaultTree'), + currentPersonalTree: anyNamed('currentPersonalTree'), + currentTeamMailboxTree: anyNamed('currentTeamMailboxTree'), + mailboxIdSelected: anyNamed('mailboxIdSelected'), + mailboxIdExpanded: anyNamed('mailboxIdExpanded'), + ), + ).thenAnswer( + (_) async => ( + allMailboxes: currentMailboxList, + defaultTree: defaultTree, + personalTree: personalTree, + teamMailboxTree: teamTree, + ), + ); + + when(uuid.v1()).thenReturn('dab123456789'); + + mailboxDashboardController.isAINeedsActionSettingEnabled.value = + false; + mailboxDashboardController.sessionCurrent = currentSession; + + // Act + await WidgetFixtures.pumpResponsiveWidget( + tester, + WidgetFixtures.makeTestableWidget( + child: MailboxView(), + ), + logicalSize: const Size(1920, 1080), + platform: TargetPlatform.macOS, + ); + + mailboxController.consumeState( + Stream.value( + Right( + GetAllMailboxSuccess( + mailboxList: currentMailboxList, + currentMailboxState: MailboxFixtures.currentState, + ), + ), + ), + ); + + await tester.pump(); + mailboxController.defaultMailboxTree.refresh(); + await tester.pump(); + + // Assert + verify( + treeBuilder.generateMailboxTreeInUI( + allMailboxes: anyNamed('allMailboxes'), + currentDefaultTree: anyNamed('currentDefaultTree'), + currentPersonalTree: anyNamed('currentPersonalTree'), + currentTeamMailboxTree: anyNamed('currentTeamMailboxTree'), + mailboxIdSelected: anyNamed('mailboxIdSelected'), + mailboxIdExpanded: anyNamed('mailboxIdExpanded'), + ), + ).called(1); + + verify( + createDefaultMailboxInteractor.execute(any, any, any), + ).called(1); + + expect(find.byType(MailboxView), findsOneWidget); + expect(find.byType(MailboxItemWidget), findsAtLeastNWidgets(1)); + + expect( + find.byWidgetPredicate( + (widget) => + widget is MailboxItemWidget && + widget.mailboxNode.item.id == + PresentationMailbox.actionRequiredFolder.id, + ), + findsNothing, + ); + + expect( + find.text(AppLocalizations().actionRequiredMailboxDisplayName), + findsNothing, + ); + + WidgetFixtures.resetResponsive(tester); + }, + ); + }); + tearDown(Get.deleteAll); }); } diff --git a/test/features/thread/presentation/widgets/email_tile_builder_ai_action_test.dart b/test/features/thread/presentation/widgets/email_tile_builder_ai_action_test.dart index 6ceece760..f1632d199 100644 --- a/test/features/thread/presentation/widgets/email_tile_builder_ai_action_test.dart +++ b/test/features/thread/presentation/widgets/email_tile_builder_ai_action_test.dart @@ -145,7 +145,8 @@ void main() { testWidgets( 'does not show AI Action tag', (tester) async { - await tester.pumpWidget( + await WidgetFixtures.pumpResponsiveWidget( + tester, WidgetFixtures.makeTestableWidget( child: EmailTileBuilder( presentationEmail: emailWithNeedsAction, @@ -154,9 +155,12 @@ void main() { isAINeedsActionEnabled: false, ), ), + logicalSize: const Size(375, 812), ); expect(find.byType(AiActionTagWidget), findsNothing); + + WidgetFixtures.resetResponsive(tester); }, ); }); diff --git a/test/fixtures/mailbox_fixtures.dart b/test/fixtures/mailbox_fixtures.dart index a1796f5e6..d596748ce 100644 --- a/test/fixtures/mailbox_fixtures.dart +++ b/test/fixtures/mailbox_fixtures.dart @@ -1,7 +1,9 @@ import 'package:jmap_dart_client/jmap/core/id.dart'; +import 'package:jmap_dart_client/jmap/core/state.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox_rights.dart'; +import 'package:model/mailbox/presentation_mailbox.dart'; class MailboxFixtures { static final inboxMailbox = Mailbox( @@ -100,4 +102,9 @@ class MailboxFixtures { static final mailboxB = Mailbox(id: MailboxId(Id('B'))); static final mailboxC = Mailbox(id: MailboxId(Id('C'))); static final mailboxD = Mailbox(id: MailboxId(Id('D'))); + + static final actionRequiredPresentationMailbox = + PresentationMailbox.actionRequiredFolder; + + static final currentState = State('2c9f1b12-b35a-43e6-9af2-0106fb53a943'); } \ No newline at end of file diff --git a/test/fixtures/session_fixtures.dart b/test/fixtures/session_fixtures.dart index 7364bf02a..32031bce4 100644 --- a/test/fixtures/session_fixtures.dart +++ b/test/fixtures/session_fixtures.dart @@ -12,6 +12,8 @@ import 'package:jmap_dart_client/jmap/core/sort/collation_identifier.dart'; import 'package:jmap_dart_client/jmap/core/state.dart'; import 'package:jmap_dart_client/jmap/core/unsigned_int.dart'; import 'package:jmap_dart_client/jmap/core/user_name.dart'; +import 'package:scribe/scribe/ai/presentation/model/ai_capability.dart'; +import 'package:scribe/scribe/ai/presentation/utils/ai_scribe_constants.dart'; import 'account_fixtures.dart'; @@ -202,4 +204,52 @@ class SessionFixtures { 'http://domain.com/eventSource?types={types}&closeAfter={closeafter}&ping={ping}'), State('2c9f1b12-b35a-43e6-9af2-0106fb53a943'), ); + + static final aliceSessionWithAICapability = Session( + { + AiScribeConstants.aiCapability: AICapability(), + }, + { + AccountFixtures.aliceAccountId: Account( + AccountName('alice@domain.tld'), + true, + false, + { + AiScribeConstants.aiCapability: AICapability(), + }, + ) + }, + { + AiScribeConstants.aiCapability: AccountFixtures.aliceAccountId, + }, + UserName('alice@domain.tld'), + Uri.parse('http://domain.com/jmap'), + Uri.parse( + 'http://domain.com/download/{accountId}/{blobId}/?type={type}&name={name}'), + Uri.parse('http://domain.com/upload/{accountId}'), + Uri.parse( + 'http://domain.com/eventSource?types={types}&closeAfter={closeafter}&ping={ping}'), + State('2c9f1b12-b35a-43e6-9af2-0106fb53a943'), + ); + + static final aliceSessionWithoutAICapability = Session( + {}, + { + AccountFixtures.aliceAccountId: Account( + AccountName('alice@domain.tld'), + true, + false, + {}, + ) + }, + {}, + UserName('alice@domain.tld'), + Uri.parse('http://domain.com/jmap'), + Uri.parse( + 'http://domain.com/download/{accountId}/{blobId}/?type={type}&name={name}'), + Uri.parse('http://domain.com/upload/{accountId}'), + Uri.parse( + 'http://domain.com/eventSource?types={types}&closeAfter={closeafter}&ping={ping}'), + State('2c9f1b12-b35a-43e6-9af2-0106fb53a943'), + ); } \ No newline at end of file