import 'package:core/data/network/config/dynamic_url_interceptors.dart'; import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/state/success.dart'; import 'package:core/presentation/utils/app_toast.dart'; import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:core/presentation/views/button/tmail_button_widget.dart'; import 'package:core/utils/platform_info.dart'; import 'package:dartz/dartz.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:get/get.dart'; import 'package:html_editor_enhanced/html_editor.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/id.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; import 'package:jmap_dart_client/jmap/identities/identity.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'package:model/email/attachment.dart'; import 'package:model/email/email_action_type.dart'; import 'package:model/extensions/session_extension.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:rich_text_composer/rich_text_composer.dart'; import 'package:tmail_ui_user/features/base/before_reconnect_manager.dart'; import 'package:tmail_ui_user/features/caching/caching_manager.dart'; import 'package:tmail_ui_user/features/composer/domain/repository/composer_repository.dart'; import 'package:tmail_ui_user/features/composer/domain/state/save_email_as_drafts_state.dart'; import 'package:tmail_ui_user/features/composer/domain/state/update_email_drafts_state.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_save_email_to_drafts_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/create_new_and_send_email_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/download_image_as_base64_interactor.dart'; import 'package:tmail_ui_user/features/composer/domain/usecases/save_composer_cache_on_web_interactor.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart'; import 'package:tmail_ui_user/features/composer/presentation/composer_view_web.dart'; import 'package:tmail_ui_user/features/composer/presentation/controller/rich_text_mobile_tablet_controller.dart'; import 'package:tmail_ui_user/features/composer/presentation/controller/rich_text_web_controller.dart'; import 'package:tmail_ui_user/features/composer/presentation/extensions/setup_selected_identity_extension.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/formatting_options_state.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/saved_composing_email.dart'; import 'package:tmail_ui_user/features/composer/presentation/model/screen_display_mode.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/print_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/save_template_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/transform_html_email_content_interactor.dart'; import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; import 'package:tmail_ui_user/features/login/data/network/interceptors/authorization_interceptors.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/delete_authority_oidc_interactor.dart'; import 'package:tmail_ui_user/features/login/domain/usecases/delete_credential_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/domain/usecases/remove_composer_cache_by_id_on_web_interactor.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/draggable_app_state.dart'; import 'package:tmail_ui_user/features/manage_account/data/local/language_cache_manager.dart'; import 'package:tmail_ui_user/features/manage_account/domain/model/preferences/ai_scribe_config.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/log_out_oidc_interactor.dart'; import 'package:tmail_ui_user/features/network_connection/presentation/network_connection_controller.dart'; import 'package:tmail_ui_user/features/server_settings/domain/usecases/get_server_setting_interactor.dart'; import 'package:tmail_ui_user/features/upload/domain/usecases/local_file_picker_interactor.dart'; import 'package:tmail_ui_user/features/upload/domain/usecases/local_image_picker_interactor.dart'; import 'package:tmail_ui_user/features/upload/presentation/controller/upload_controller.dart'; import 'package:tmail_ui_user/features/upload/presentation/model/upload_file_state.dart'; import 'package:tmail_ui_user/main/bindings/network/binding_tag.dart'; import 'package:tmail_ui_user/main/exceptions/cache_exception_thrower.dart'; import 'package:tmail_ui_user/main/utils/app_config.dart'; import 'package:tmail_ui_user/main/utils/toast_manager.dart'; import 'package:tmail_ui_user/main/utils/twake_app_manager.dart'; import 'package:uuid/uuid.dart'; import '../../../fixtures/account_fixtures.dart'; import '../../../fixtures/session_fixtures.dart'; import '../../../fixtures/widget_fixtures.dart'; import '../../../mocks/mock_web_view_platform.dart'; import 'composer_controller_test.mocks.dart'; mockControllerCallback() => InternalFinalCallback(callback: () {}); const fallbackGenerators = { #onStart: mockControllerCallback, #onDelete: mockControllerCallback, }; class MockRichTextWebController extends Mock implements RichTextWebController { @override Rx get formattingOptionsState => FormattingOptionsState.disabled.obs; @override bool get isFormattingOptionsEnabled => formattingOptionsState.value == FormattingOptionsState.enabled; @override HtmlEditorController get editorController => MockHtmlEditorController(); @override bool get codeViewEnabled => false; } class MockMailboxDashBoardController extends Mock implements MailboxDashBoardController { @override InternalFinalCallback get onStart => mockControllerCallback(); @override InternalFinalCallback get onDelete => mockControllerCallback(); @override Rxn get accountId => Rxn(AccountFixtures.aliceAccountId); @override Session? get sessionCurrent => SessionFixtures.aliceSession; @override RxString get ownEmailAddress => SessionFixtures.aliceSession.getOwnEmailAddressOrEmpty().obs; @override Rxn get attachmentDraggableAppState => Rxn(DraggableAppState.inActive); @override bool get isAttachmentDraggableAppActive => attachmentDraggableAppState.value == DraggableAppState.active; @override Rxn get localFileDraggableAppState => Rxn(DraggableAppState.inActive); @override bool get isLocalFileDraggableAppActive => localFileDraggableAppState.value == DraggableAppState.active; @override Map get mapDefaultMailboxIdByRole => {PresentationMailbox.roleDrafts: MailboxId(Id('value'))}; @override String get baseDownloadUrl => ''; @override int get minInputLengthAutocomplete => AppConfig.defaultMinInputLengthAutocomplete; @override Map get mapMailboxById => {}; @override RxBool get isAppGridDialogDisplayed => false.obs; @override RxBool get isDrawerOpened => false.obs; @override RxBool get isContextMenuOpened => false.obs; @override RxBool get isPopupMenuOpened => false.obs; @override Rx get cachedAIScribeConfig => AIScribeConfig.initial().obs; @override bool isAIScribeEndpointAvailable({Session? session, AccountId? accountId}) { return false; } } @GenerateNiceMocks([ // Base controller mock specs MockSpec(), MockSpec(), MockSpec(), MockSpec(), MockSpec(), MockSpec(), MockSpec(), MockSpec(), MockSpec(), MockSpec(), MockSpec(), MockSpec(), MockSpec(), // Composer controller mock specs MockSpec(), MockSpec(), MockSpec(), MockSpec(), MockSpec(fallbackGenerators: fallbackGenerators), MockSpec(), MockSpec(), MockSpec(), MockSpec(), MockSpec(), MockSpec(), MockSpec(), MockSpec(), MockSpec(), MockSpec(), // Additional Getx dependencies mock specs MockSpec(fallbackGenerators: fallbackGenerators), MockSpec(), MockSpec(fallbackGenerators: fallbackGenerators), MockSpec(), // Additional misc dependencies mock specs MockSpec(), MockSpec(), ]) void main() { TestWidgetsFlutterBinding.ensureInitialized(); // Declaration base controller late MockCachingManager mockCachingManager; late MockLanguageCacheManager mockLanguageCacheManager; late MockAuthorizationInterceptors mockAuthorizationInterceptors; late MockDynamicUrlInterceptors mockDynamicUrlInterceptors; late MockDeleteCredentialInteractor mockDeleteCredentialInteractor; late MockLogoutOidcInteractor mockLogoutOidcInteractor; late MockDeleteAuthorityOidcInteractor mockDeleteAuthorityOidcInteractor; late MockAppToast mockAppToast; late MockUuid mockUuid; late MockToastManager mockToastManager; late MockTwakeAppManager mockTwakeAppManager; // Declaration composer controller late ComposerController? composerController; late MockLocalFilePickerInteractor mockLocalFilePickerInteractor; late MockLocalImagePickerInteractor mockLocalImagePickerInteractor; late MockGetEmailContentInteractor mockGetEmailContentInteractor; late MockGetAllIdentitiesInteractor mockGetAllIdentitiesInteractor; late MockUploadController mockUploadController; late MockRemoveComposerCacheByIdOnWebInteractor mockRemoveComposerCacheByIdOnWebInteractor; late MockSaveComposerCacheOnWebInteractor mockSaveComposerCacheOnWebInteractor; late MockDownloadImageAsBase64Interactor mockDownloadImageAsBase64Interactor; late MockTransformHtmlEmailContentInteractor mockTransformHtmlEmailContentInteractor; late MockGetServerSettingInteractor mockGetServerSettingInteractor; late MockCreateNewAndSendEmailInteractor mockCreateNewAndSendEmailInteractor; late MockCreateNewAndSaveEmailToDraftsInteractor mockCreateNewAndSaveEmailToDraftsInteractor; late MockPrintEmailInteractor mockPrintEmailInteractor; late MockComposerRepository mockComposerRepository; late MockSaveTemplateEmailInteractor mockSaveTemplateEmailInteractor; // Declaration Getx dependencies final mockMailboxDashBoardController = MockMailboxDashBoardController(); final mockNetworkConnectionController = MockNetworkConnectionController(); final mockBeforeReconnectManager = MockBeforeReconnectManager(); final mockRichTextMobileTabletController = MockRichTextMobileTabletController(); final mockRichTextWebController = MockRichTextWebController(); final mockCacheExceptionThrower = MockCacheExceptionThrower(); // Declaration misc dependencies late MockHtmlEditorApi mockHtmlEditorApi; setUp(() { Get.testMode = true; // Mock base controller mockCachingManager = MockCachingManager(); mockLanguageCacheManager = MockLanguageCacheManager(); mockAuthorizationInterceptors = MockAuthorizationInterceptors(); mockDynamicUrlInterceptors = MockDynamicUrlInterceptors(); mockDeleteCredentialInteractor = MockDeleteCredentialInteractor(); mockLogoutOidcInteractor = MockLogoutOidcInteractor(); mockDeleteAuthorityOidcInteractor = MockDeleteAuthorityOidcInteractor(); mockAppToast = MockAppToast(); mockUuid = MockUuid(); mockToastManager = MockToastManager(); mockTwakeAppManager = MockTwakeAppManager(); Get.put(mockCachingManager); Get.put(mockLanguageCacheManager); Get.put(mockAuthorizationInterceptors); Get.put( mockAuthorizationInterceptors, tag: BindingTag.isolateTag, ); Get.put(mockDynamicUrlInterceptors); Get.put(mockDeleteCredentialInteractor); Get.put(mockLogoutOidcInteractor); Get.put(mockDeleteAuthorityOidcInteractor); Get.put(mockAppToast); Get.put(ImagePaths()); Get.put(ResponsiveUtils()); Get.put(mockUuid); Get.put(mockToastManager); Get.put(mockTwakeAppManager); // Mock Getx controllers Get.put(mockMailboxDashBoardController); Get.put(mockNetworkConnectionController); Get.put(mockBeforeReconnectManager); Get.put(mockRichTextMobileTabletController); Get.put(mockCacheExceptionThrower); // Mock composer controller mockLocalFilePickerInteractor = MockLocalFilePickerInteractor(); mockLocalImagePickerInteractor = MockLocalImagePickerInteractor(); mockGetEmailContentInteractor = MockGetEmailContentInteractor(); mockGetAllIdentitiesInteractor = MockGetAllIdentitiesInteractor(); mockUploadController = MockUploadController(); mockRemoveComposerCacheByIdOnWebInteractor = MockRemoveComposerCacheByIdOnWebInteractor(); mockSaveComposerCacheOnWebInteractor = MockSaveComposerCacheOnWebInteractor(); mockDownloadImageAsBase64Interactor = MockDownloadImageAsBase64Interactor(); mockTransformHtmlEmailContentInteractor = MockTransformHtmlEmailContentInteractor(); mockGetServerSettingInteractor = MockGetServerSettingInteractor(); mockCreateNewAndSendEmailInteractor = MockCreateNewAndSendEmailInteractor(); mockCreateNewAndSaveEmailToDraftsInteractor = MockCreateNewAndSaveEmailToDraftsInteractor(); mockPrintEmailInteractor = MockPrintEmailInteractor(); mockComposerRepository = MockComposerRepository(); mockSaveTemplateEmailInteractor = MockSaveTemplateEmailInteractor(); composerController = ComposerController( mockLocalFilePickerInteractor, mockLocalImagePickerInteractor, mockGetEmailContentInteractor, mockGetAllIdentitiesInteractor, mockUploadController, mockRemoveComposerCacheByIdOnWebInteractor, mockSaveComposerCacheOnWebInteractor, mockDownloadImageAsBase64Interactor, mockTransformHtmlEmailContentInteractor, mockGetServerSettingInteractor, mockCreateNewAndSendEmailInteractor, mockCreateNewAndSaveEmailToDraftsInteractor, mockPrintEmailInteractor, mockComposerRepository, mockSaveTemplateEmailInteractor, ); mockHtmlEditorApi = MockHtmlEditorApi(); }); tearDown(() { Get.reset(); composerController = null; }); group('ComposerController test:', () { group('hash draft email test:', () { const emailContent = 'some email content'; const emailSubject = 'some email subject'; final toRecipient = EmailAddress('to', 'to@linagora.com'); final ccRecipient = EmailAddress('cc', 'cc@linagora.com'); final bccRecipient = EmailAddress('bcc', 'bcc@linagora.com'); final replyToRecipient = EmailAddress('replyTo', 'replyTo@linagora.com'); final identity = Identity(); final attachment = Attachment(); const alwaysReadReceiptEnabled = false; const isMarkAsImportant = false; group('email action type is EmailActionType.compose:', () { test( 'Should update _savedEmailDraftHash\n' 'When screenDisplayMode is normal', () async { // arrange final composerArguments = ComposerArguments( emailActionType: EmailActionType.compose, displayMode: ScreenDisplayMode.normal, identities: [identity], selectedIdentityId: identity.id, ); composerController?.composerArguments.value = composerArguments; composerController?.richTextMobileTabletController = mockRichTextMobileTabletController; composerController?.subjectEmail.value = emailSubject; composerController?.listToEmailAddress = [toRecipient]; composerController?.listCcEmailAddress = [ccRecipient]; composerController?.listBccEmailAddress = [bccRecipient]; composerController?.listReplyToEmailAddress = [replyToRecipient]; composerController?.hasRequestReadReceipt.value = alwaysReadReceiptEnabled; composerController?.isMarkAsImportant.value = isMarkAsImportant; composerController?.screenDisplayMode.value = composerArguments.displayMode; composerController?.currentEmailActionType = composerArguments.emailActionType; composerController?.listFromIdentities.value = composerArguments.identities!; when(mockRichTextMobileTabletController.htmlEditorApi).thenReturn(mockHtmlEditorApi); when(mockHtmlEditorApi.getText()).thenAnswer((_) async => emailContent); when(mockUploadController.attachmentsUploaded).thenReturn([attachment]); when(mockComposerRepository.removeCollapsedExpandedSignatureEffect( emailContent: anyNamed('emailContent'), )).thenAnswer((_) async => emailContent); final savedEmailDraft = SavedComposingEmail( content: emailContent, subject: emailSubject, toRecipients: {toRecipient}, ccRecipients: {ccRecipient}, bccRecipients: {bccRecipient}, replyToRecipients: {replyToRecipient}, identity: identity, attachments: [attachment], hasReadReceipt: alwaysReadReceiptEnabled, isMarkAsImportant: isMarkAsImportant, ); // act composerController?.setupSelectedIdentity(); await untilCalled(mockHtmlEditorApi.onDocumentChanged()); await untilCalled(mockHtmlEditorApi.getText()); await untilCalled( mockComposerRepository.removeCollapsedExpandedSignatureEffect( emailContent: anyNamed('emailContent'))); // assert expect( composerController?.savedEmailDraftHash, equals(savedEmailDraft.asString().hashCode), ); }); test( 'Should update _savedEmailDraftHash\n' 'When screenDisplayMode is minimize', () async { // arrange final composerArguments = ComposerArguments( emailActionType: EmailActionType.compose, displayMode: ScreenDisplayMode.minimize, identities: [identity], selectedIdentityId: identity.id, ); composerController?.composerArguments.value = composerArguments; composerController?.richTextMobileTabletController = mockRichTextMobileTabletController; composerController?.subjectEmail.value = emailSubject; composerController?.listToEmailAddress = [toRecipient]; composerController?.listCcEmailAddress = [ccRecipient]; composerController?.listBccEmailAddress = [bccRecipient]; composerController?.listReplyToEmailAddress = [replyToRecipient]; composerController?.hasRequestReadReceipt.value = alwaysReadReceiptEnabled; composerController?.isMarkAsImportant.value = isMarkAsImportant; composerController?.screenDisplayMode.value = composerArguments.displayMode; composerController?.currentEmailActionType = composerArguments.emailActionType; composerController?.listFromIdentities.value = composerArguments.identities!; when(mockRichTextMobileTabletController.htmlEditorApi).thenReturn(mockHtmlEditorApi); when(mockHtmlEditorApi.getText()).thenAnswer((_) async => emailContent); when(mockUploadController.attachmentsUploaded).thenReturn([attachment]); when(mockComposerRepository.removeCollapsedExpandedSignatureEffect( emailContent: anyNamed('emailContent'), )).thenAnswer((_) async => emailContent); final savedEmailDraft = SavedComposingEmail( content: emailContent, subject: emailSubject, toRecipients: {toRecipient}, ccRecipients: {ccRecipient}, bccRecipients: {bccRecipient}, replyToRecipients: {replyToRecipient}, identity: identity, attachments: [attachment], hasReadReceipt: alwaysReadReceiptEnabled, isMarkAsImportant: isMarkAsImportant, ); // act composerController?.setupSelectedIdentityWithoutApplySignature(); await untilCalled(mockHtmlEditorApi.getText()); await untilCalled( mockComposerRepository.removeCollapsedExpandedSignatureEffect( emailContent: anyNamed('emailContent'))); // assert expect( composerController?.savedEmailDraftHash, equals(savedEmailDraft.asString().hashCode), ); }); testWidgets( 'Should update _savedEmailDraftHash\n' 'When user click save draft button\n' 'And SaveEmailAsDraftsSuccess is returned', (tester) async { await tester.runAsync(() async { // arrange PlatformInfo.isTestingForWeb = true; InAppWebViewPlatform.instance = MockWebViewPlatform(); when(mockUploadController.uploadInlineViewState).thenReturn( Rx(Right(UIState.idle))); when(mockUploadController.listUploadAttachments).thenReturn( RxList()); Get.put(composerController!); composerController?.richTextWebController = mockRichTextWebController; composerController?.setTextEditorWeb(emailContent); composerController?.subjectEmail.value = emailSubject; composerController?.listToEmailAddress = [toRecipient]; composerController?.listCcEmailAddress = [ccRecipient]; composerController?.listBccEmailAddress = [bccRecipient]; composerController?.listReplyToEmailAddress = [replyToRecipient]; when(mockUploadController.attachmentsUploaded).thenReturn([attachment]); when(mockComposerRepository.removeCollapsedExpandedSignatureEffect( emailContent: anyNamed('emailContent'), )).thenAnswer((_) async => emailContent); final selectedIdentity = Identity(id: IdentityId(Id('alice'))); composerController?.identitySelected.value = selectedIdentity; composerController?.composerArguments.value = ComposerArguments(); when( mockCreateNewAndSaveEmailToDraftsInteractor.execute( createEmailRequest: anyNamed('createEmailRequest'), cancelToken: anyNamed('cancelToken'))) .thenAnswer((_) => Stream.value( Right(SaveEmailAsDraftsSuccess(EmailId(Id('123')), null)))); final savedEmailDraft = SavedComposingEmail( content: emailContent, subject: emailSubject, toRecipients: {toRecipient}, ccRecipients: {ccRecipient}, bccRecipients: {bccRecipient}, replyToRecipients: {replyToRecipient}, identity: selectedIdentity, attachments: [attachment], hasReadReceipt: false, isMarkAsImportant: false, ); await tester.pumpWidget(WidgetFixtures.makeTestableWidget( child: const Stack(children: [ComposerView()]))); await tester.pump(); // act final saveAsDraftButton = find.ancestor( of: find.byType(InkWell), matching: find.byWidgetPredicate( (widget) => widget is TMailButtonWidget && widget.icon == ImagePaths().icSaveToDraft)); await tester.tap(saveAsDraftButton); await tester.pump(); await untilCalled( mockCreateNewAndSaveEmailToDraftsInteractor.execute( createEmailRequest: anyNamed('createEmailRequest'), cancelToken: anyNamed('cancelToken'))); // assert expect( composerController?.savedEmailDraftHash, equals(savedEmailDraft.asString().hashCode), ); // tear down PlatformInfo.isTestingForWeb = false; }); }); testWidgets( 'Should update _savedEmailDraftHash\n' 'When user click save draft button\n' 'And UpdateEmailDraftsSuccess is returned', (tester) async { await tester.runAsync(() async { // arrange PlatformInfo.isTestingForWeb = true; InAppWebViewPlatform.instance = MockWebViewPlatform(); when(mockUploadController.uploadInlineViewState).thenReturn( Rx(Right(UIState.idle))); when(mockUploadController.listUploadAttachments).thenReturn( RxList()); Get.put(composerController!); composerController?.richTextWebController = mockRichTextWebController; composerController?.onChangeTextEditorWeb(emailContent); composerController?.subjectEmail.value = emailSubject; composerController?.listToEmailAddress = [toRecipient]; composerController?.listCcEmailAddress = [ccRecipient]; composerController?.listBccEmailAddress = [bccRecipient]; composerController?.listReplyToEmailAddress = [replyToRecipient]; when(mockUploadController.attachmentsUploaded).thenReturn([attachment]); when(mockComposerRepository.removeCollapsedExpandedSignatureEffect( emailContent: anyNamed('emailContent'), )).thenAnswer((_) async => emailContent); final selectedIdentity = Identity(id: IdentityId(Id('alice'))); composerController?.identitySelected.value = selectedIdentity; composerController?.composerArguments.value = ComposerArguments(); when( mockCreateNewAndSaveEmailToDraftsInteractor.execute( createEmailRequest: anyNamed('createEmailRequest'), cancelToken: anyNamed('cancelToken'))) .thenAnswer((_) => Stream.value( Right(UpdateEmailDraftsSuccess(EmailId(Id('123')))))); final savedEmailDraft = SavedComposingEmail( content: emailContent, subject: emailSubject, toRecipients: {toRecipient}, ccRecipients: {ccRecipient}, bccRecipients: {bccRecipient}, replyToRecipients: {replyToRecipient}, identity: selectedIdentity, attachments: [attachment], hasReadReceipt: false, isMarkAsImportant: false, ); await tester.pumpWidget(WidgetFixtures.makeTestableWidget( child: const Stack(children: [ComposerView()]))); await tester.pump(); // act final saveAsDraftButton = find.ancestor( of: find.byType(InkWell), matching: find.byWidgetPredicate( (widget) => widget is TMailButtonWidget && widget.icon == ImagePaths().icSaveToDraft)); await tester.tap(saveAsDraftButton); await tester.pump(); await untilCalled( mockCreateNewAndSaveEmailToDraftsInteractor.execute( createEmailRequest: anyNamed('createEmailRequest'), cancelToken: anyNamed('cancelToken'))); // assert expect( composerController?.savedEmailDraftHash, equals(savedEmailDraft.asString().hashCode), ); // tear down PlatformInfo.isTestingForWeb = false; }); }); }); group('email action type is EmailActionType.editDraft:', () { test( 'Should update _savedEmailDraftHash\n' 'When screenDisplayMode is normal', () async { // arrange final composerArguments = ComposerArguments( emailActionType: EmailActionType.editDraft, displayMode: ScreenDisplayMode.normal, identities: [identity], selectedIdentityId: identity.id, ); composerController?.composerArguments.value = composerArguments; composerController?.richTextMobileTabletController = mockRichTextMobileTabletController; composerController?.subjectEmail.value = emailSubject; composerController?.listToEmailAddress = [toRecipient]; composerController?.listCcEmailAddress = [ccRecipient]; composerController?.listBccEmailAddress = [bccRecipient]; composerController?.listReplyToEmailAddress = [replyToRecipient]; composerController?.hasRequestReadReceipt.value = alwaysReadReceiptEnabled; composerController?.isMarkAsImportant.value = isMarkAsImportant; composerController?.screenDisplayMode.value = composerArguments.displayMode; composerController?.currentEmailActionType = composerArguments.emailActionType; composerController?.listFromIdentities.value = composerArguments.identities!; composerController?.identitySelected.value = null; when(mockRichTextMobileTabletController.htmlEditorApi).thenReturn(mockHtmlEditorApi); when(mockHtmlEditorApi.getText()).thenAnswer((_) async => emailContent); when(mockUploadController.attachmentsUploaded).thenReturn([attachment]); when(mockComposerRepository.removeCollapsedExpandedSignatureEffect( emailContent: anyNamed('emailContent'), )).thenAnswer((_) async => emailContent); final savedEmailDraft = SavedComposingEmail( content: emailContent, subject: emailSubject, toRecipients: {toRecipient}, ccRecipients: {ccRecipient}, bccRecipients: {bccRecipient}, replyToRecipients: {replyToRecipient}, identity: identity, attachments: [attachment], hasReadReceipt: alwaysReadReceiptEnabled, isMarkAsImportant: isMarkAsImportant, ); // act composerController?.setupSelectedIdentity(); await untilCalled(mockHtmlEditorApi.getText()); await untilCalled( mockComposerRepository.removeCollapsedExpandedSignatureEffect( emailContent: anyNamed('emailContent'))); // assert expect( composerController?.savedEmailDraftHash, equals(savedEmailDraft.asString().hashCode), ); }); test( 'Should update _savedEmailDraftHash\n' 'When screenDisplayMode is minimize', () async { // arrange final composerArguments = ComposerArguments( emailActionType: EmailActionType.editDraft, displayMode: ScreenDisplayMode.minimize, identities: [identity], selectedIdentityId: identity.id, ); composerController?.composerArguments.value = composerArguments; composerController?.richTextMobileTabletController = mockRichTextMobileTabletController; composerController?.subjectEmail.value = emailSubject; composerController?.listToEmailAddress = [toRecipient]; composerController?.listCcEmailAddress = [ccRecipient]; composerController?.listBccEmailAddress = [bccRecipient]; composerController?.listReplyToEmailAddress = [replyToRecipient]; composerController?.hasRequestReadReceipt.value = alwaysReadReceiptEnabled; composerController?.isMarkAsImportant.value = isMarkAsImportant; composerController?.screenDisplayMode.value = composerArguments.displayMode; composerController?.currentEmailActionType = composerArguments.emailActionType; composerController?.listFromIdentities.value = composerArguments.identities!; composerController?.identitySelected.value = null; when(mockRichTextMobileTabletController.htmlEditorApi).thenReturn(mockHtmlEditorApi); when(mockHtmlEditorApi.getText()).thenAnswer((_) async => emailContent); when(mockUploadController.attachmentsUploaded).thenReturn([attachment]); when(mockComposerRepository.removeCollapsedExpandedSignatureEffect( emailContent: anyNamed('emailContent'), )).thenAnswer((_) async => emailContent); final savedEmailDraft = SavedComposingEmail( content: emailContent, subject: emailSubject, toRecipients: {toRecipient}, ccRecipients: {ccRecipient}, bccRecipients: {bccRecipient}, replyToRecipients: {replyToRecipient}, identity: identity, attachments: [attachment], hasReadReceipt: alwaysReadReceiptEnabled, isMarkAsImportant: isMarkAsImportant, ); // act composerController?.setupSelectedIdentityWithoutApplySignature(); await untilCalled(mockHtmlEditorApi.getText()); await untilCalled( mockComposerRepository.removeCollapsedExpandedSignatureEffect( emailContent: anyNamed('emailContent'))); // assert expect( composerController?.savedEmailDraftHash, equals(savedEmailDraft.asString().hashCode), ); }); }); }); }); }