TF-4058 Update E2E test to compatible with flutter version 3.32.8

This commit is contained in:
dab246
2025-10-14 15:20:22 +07:00
committed by Dat H. Pham
parent 81ce3f6b04
commit d686b66f75
24 changed files with 74 additions and 48 deletions
@@ -7,7 +7,7 @@ on:
env:
JAVA_VERSION: 17
FLUTTER_VERSION: 3.27.4
FLUTTER_VERSION: 3.32.8
jobs:
mobile_integration_test:
@@ -1,5 +1,6 @@
import 'package:core/utils/app_logger.dart';
import 'package:core/utils/platform_info.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
@@ -10,6 +11,10 @@ mixin ImageLoaderMixin {
required String imagePath,
double? imageSize
}) {
log('$runtimeType::buildImage: imagePath = $imagePath');
if (PlatformInfo.isIntegrationTesting) {
return buildNoImage(imageSize ?? 150);
}
if (isImageNetworkLink(imagePath) && isImageSVG(imagePath)) {
return SvgPicture.network(
imagePath,
@@ -19,6 +24,9 @@ mixin ImageLoaderMixin {
placeholderBuilder: (_) {
return const CupertinoActivityIndicator();
},
errorBuilder: (_, __, ___) {
return buildNoImage(imageSize ?? 150);
},
);
} else if (isImageNetworkLink(imagePath)) {
return Image.network(
@@ -27,16 +35,10 @@ mixin ImageLoaderMixin {
width: imageSize ?? 150,
height: imageSize ?? 150,
loadingBuilder: (_, child, loadingProgress) {
if (loadingProgress != null &&
loadingProgress.cumulativeBytesLoaded != loadingProgress.expectedTotalBytes) {
return const Center(
child: CupertinoActivityIndicator(),
);
}
return child;
if (loadingProgress == null) return child;
return const Center(child: CupertinoActivityIndicator());
},
errorBuilder: (context, error, stackTrace) {
logError('ImageLoaderMixin::buildImage:Exception = $error');
errorBuilder: (_, __, ___) {
return buildNoImage(imageSize ?? 150);
},
);
@@ -4,7 +4,7 @@ import 'dart:io' hide HttpClient;
import 'package:collection/collection.dart';
import 'package:core/utils/app_logger.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:get/get.dart';
import 'package:jmap_dart_client/http/http_client.dart';
import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart';
@@ -282,7 +282,7 @@ mixin ScenarioUtilsMixin {
IdentityInteractorsBindings().dispose();
}
Future<void> hideKeyboard() async {
await SystemChannels.textInput.invokeMethod('TextInput.hide');
void hideKeyboard() {
FocusManager.instance.primaryFocus?.unfocus();
}
}
@@ -14,6 +14,7 @@ import 'package:tmail_ui_user/features/composer/domain/state/download_image_as_b
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
import 'package:tmail_ui_user/features/composer/presentation/composer_view.dart';
import 'package:tmail_ui_user/features/composer/presentation/view/mobile/mobile_editor_view.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/list_recipients_collapsed_widget.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/mobile/app_bar_composer_widget.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/mobile/from_composer_mobile_widget.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/recipient_composer_widget.dart';
@@ -29,6 +30,10 @@ import '../extensions/patrol_finder_extension.dart';
class ComposerRobot extends CoreRobot {
ComposerRobot(super.$);
Future<void> expandRecipientsFields() async {
await $(RecipientsCollapsedComposerWidget).$(GestureDetector).tap();
}
Future<void> addRecipientIntoField({
required PrefixEmailAddress prefixEmailAddress,
required String email,
+1 -1
View File
@@ -16,7 +16,7 @@ class EmailRobot extends CoreRobot {
}
Future<void> tapDownloadAllButton() async {
await $(AppLocalizations().archiveAndDownload).tap();
await $(#download_all_attachments_button).tap();
await $.pumpAndSettle();
}
@@ -16,6 +16,7 @@ class AppGridScenario extends BaseTestScenario {
@override
Future<void> runTestLogic() async {
PlatformInfo.isIntegrationTesting = true;
final threadRobot = ThreadRobot($);
final mailboxMenuRobot = MailboxMenuRobot($);
final appGridRobot = AppGridRobot($);
@@ -52,6 +53,7 @@ class AppGridScenario extends BaseTestScenario {
} else if (PlatformInfo.isIOS) {
await _expectMailboxViewInVisible();
}
PlatformInfo.isIntegrationTesting = false;
}
Future<void> _expectMailboxViewVisible() => expectViewVisible($(MailboxView));
@@ -31,7 +31,7 @@ class ComposerUploadAttachmentAndInlineImageScenario extends BaseTestScenario {
await _expectAttachment(pngName);
await composerRobot.addInline(png);
await $.pumpAndSettle();
await $.pumpAndSettle(duration: const Duration(seconds: 1));
await _expectInline();
await composerRobot.addAttachment(png);
@@ -1,9 +1,11 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:model/email/prefix_email_address.dart';
import 'package:tmail_ui_user/features/composer/presentation/composer_view.dart';
import 'package:tmail_ui_user/features/composer/presentation/widgets/recipient_composer_widget.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import '../../base/base_test_scenario.dart';
import '../../robots/composer_robot.dart';
import '../../robots/email_robot.dart';
import '../../robots/mailbox_menu_robot.dart';
import '../../robots/thread_robot.dart';
@@ -19,6 +21,7 @@ class ReplyToOwnSentEmailScenario extends BaseTestScenario {
final threadRobot = ThreadRobot($);
final mailboxMenuRobot = MailboxMenuRobot($);
final emailRobot = EmailRobot($);
final composerRobot = ComposerRobot($);
final sendEmailScenario = SendEmailScenario($, customSubject: subject);
final appLocalizations = AppLocalizations();
@@ -29,9 +32,20 @@ class ReplyToOwnSentEmailScenario extends BaseTestScenario {
);
await threadRobot.openEmailWithSubject(subject);
await emailRobot.onTapReplyEmail();
await _expectComposerViewVisible();
await composerRobot.grantContactPermission();
await composerRobot.expandRecipientsFields();
await $.pumpAndSettle();
_expectToFieldContainListEmailAddressCorrectly();
}
Future<void> _expectComposerViewVisible() async {
await expectViewVisible($(ComposerView));
}
void _expectToFieldContainListEmailAddressCorrectly() {
expect(
$(RecipientComposerWidget).which<RecipientComposerWidget>((widget) =>
@@ -49,6 +49,9 @@ class ComposeEmailFromEmailAddressScenario extends BaseTestScenario {
await composerRobot.grantContactPermission();
await composerRobot.expandRecipientsFields();
await $.pumpAndSettle();
await _expectToFieldContainListEmailAddressCorrectly(emailUser);
}
@@ -1,9 +1,8 @@
import 'package:core/presentation/views/html_viewer/html_content_viewer_widget.dart';
import 'package:core/utils/app_logger.dart';
import 'package:core/utils/platform_info.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:tmail_ui_user/features/email/presentation/controller/single_email_controller.dart';
import 'package:tmail_ui_user/features/email/presentation/email_view.dart';
import 'package:tmail_ui_user/features/thread/presentation/widgets/email_tile_builder.dart';
import '../../base/base_test_scenario.dart';
@@ -121,10 +120,12 @@ class DeformedInlinedImageScenario extends BaseTestScenario {
}
Future<void> _expectEmailViewDisplaysNormalizedInlineImages() async {
GlobalKey<HtmlContentViewState>? htmlContentViewKey;
HtmlContentViewer? htmlContentViewer;
await $(HtmlContentViewer)
.which<HtmlContentViewer>((view) {
htmlContentViewer = view;
htmlContentViewKey = view.key as GlobalKey<HtmlContentViewState>;
return true;
})
.first
@@ -133,17 +134,6 @@ class DeformedInlinedImageScenario extends BaseTestScenario {
log('DeformedInlinedImageScenario::_expectEmailViewDisplaysNormalizedInlineImages:initialWidth = ${htmlContentViewer?.initialWidth}');
expect(htmlContentViewer?.contentHtml.isNotEmpty, isTrue);
SingleEmailController? emailController;
await $(EmailView)
.which<EmailView>((view) {
emailController = view.controller;
return true;
})
.first
.tap();
expect(emailController, isNotNull);
final htmlContentViewKey = emailController?.htmlContentViewKey;
expect(htmlContentViewKey, isNotNull);
final result = await htmlContentViewKey!.currentState!.webViewController.evaluateJavascript(
@@ -55,6 +55,10 @@ class ForwardingEmailLostAttachmentsScenario extends BaseTestScenario {
await _expectComposerViewVisible();
await composerRobot.grantContactPermission();
await composerRobot.expandRecipientsFields();
await $.pumpAndSettle();
await composerRobot.addRecipientIntoField(
prefixEmailAddress: PrefixEmailAddress.to,
email: emailUser,
@@ -44,6 +44,9 @@ class ReplyAllEmailScenario extends BaseTestScenario {
await composerRobot.grantContactPermission();
await composerRobot.expandRecipientsFields();
await $.pumpAndTrySettle();
await _expectComposerSubjectDisplayedCorrectly(appLocalizations);
await _expectToFieldContainListEmailAddressCorrectly();
await _expectCcFieldContainListEmailAddressCorrectly();
@@ -44,6 +44,9 @@ class ReplyEmailWithReplyToScenario extends BaseTestScenario {
await composerRobot.grantContactPermission();
await composerRobot.expandRecipientsFields();
await $.pumpAndTrySettle();
await _expectComposerSubjectDisplayedCorrectly(appLocalizations);
await _expectToFieldContainReplyToEmailAddress();
}
@@ -44,6 +44,9 @@ class ReplyEmailWithoutReplyToScenario extends BaseTestScenario {
await composerRobot.grantContactPermission();
await composerRobot.expandRecipientsFields();
await $.pumpAndTrySettle();
await _expectComposerSubjectDisplayedCorrectly(appLocalizations);
await _expectToFieldContainFromEmailAddress();
}
@@ -44,6 +44,9 @@ class ReplyToListEmailScenario extends BaseTestScenario {
await composerRobot.grantContactPermission();
await composerRobot.expandRecipientsFields();
await $.pumpAndTrySettle();
await _expectComposerSubjectDisplayedCorrectly(appLocalizations);
await _expectToFieldContainListPostEmailAddress();
}
@@ -70,6 +70,7 @@ class LongPressEmptyAndRecoverSpamScenario extends BaseTestScenario {
}
Future<void> _expectEmailWithSubjectVisible(String subject) async {
await $.scrollUntilVisible(finder: $(subject));
await expectViewVisible($(subject));
}
@@ -68,6 +68,7 @@ class LongPressEmptyAndRecoverTrashScenario extends BaseTestScenario {
}
Future<void> _expectEmailWithSubjectVisible(String subject) async {
await $.scrollUntilVisible(finder: $(subject));
await expectViewVisible($(subject));
}
@@ -37,11 +37,11 @@ class PullToRefreshScenario extends BaseTestScenario {
_expectEmailWithSubjectInvisible(visibleAfterPullToRefresh);
await threadRobot.pullToRefreshByEmailSubject(visibleBeforePullToRefresh);
_expectEmailWithSubjectVisible(visibleAfterPullToRefresh);
await _expectEmailWithSubjectVisible(visibleAfterPullToRefresh);
}
_expectEmailWithSubjectVisible(String subject) {
expect($(subject), findsOneWidget);
Future<void> _expectEmailWithSubjectVisible(String subject) async {
await expectViewVisible($(subject));
}
_expectEmailWithSubjectInvisible(String subject) {
@@ -46,6 +46,9 @@ class ReplyEmailWithContentContainImageBase64DataScenario extends BaseTestScenar
await composerRobot.grantContactPermission();
await composerRobot.expandRecipientsFields();
await $.pumpAndSettle();
await composerRobot.addRecipientIntoField(
prefixEmailAddress: PrefixEmailAddress.to,
email: emailUser,
@@ -17,11 +17,12 @@ class SaveAsTemplateScenario extends BaseTestScenario {
await composerRobot.grantContactPermission();
await composerRobot.saveAsTemplate();
await $.pumpAndTrySettle();
await _expectSaveToastSuccessVisible();
await composerRobot.addSubject('test subject');
await hideKeyboard();
hideKeyboard();
await $.pumpAndTrySettle(duration: const Duration(seconds: 1));
await composerRobot.saveAsTemplate();
await _expectUpdateToastSuccessVisible();
@@ -14,7 +14,7 @@ class PersistFilterWhenChangeSearchInputTextScenario
Future<void> runTestLogic() async {
const email = String.fromEnvironment('BASIC_AUTH_EMAIL');
const subject = 'Persist search filter';
const queryStringFirst = 'Persist';
const queryStringFirst = 'Persist search filter';
const queryStringSecond = 'Persist search';
final threadRobot = ThreadRobot($);
@@ -68,6 +68,7 @@ class AttachmentsInfo extends StatelessWidget {
),
if (onTapDownloadAllButton != null)
TMailButtonWidget(
key: const Key('download_all_attachments_button'),
text: AppLocalizations.of(context).downloadAll,
icon: !responsiveUtils.isMobile(context)
? imagePaths.icDownloadAttachment
+1 -7
View File
@@ -1,5 +1,5 @@
{
"@@last_modified": "2025-10-07T12:02:25.245876",
"@@last_modified": "2025-10-14T15:18:48.964794",
"initializing_data": "Initializing data...",
"@initializing_data": {
"type": "text",
@@ -4592,12 +4592,6 @@
"placeholders_order": [],
"placeholders": {}
},
"archiveAndDownload": "Archive and download",
"@archiveAndDownload": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"creatingAnArchiveForDownloading": "Creating an archive for downloading",
"@creatingAnArchiveForDownloading": {
"type": "text",
@@ -4838,13 +4838,6 @@ class AppLocalizations {
);
}
String get archiveAndDownload {
return Intl.message(
'Archive and download',
name: 'archiveAndDownload',
);
}
String get creatingAnArchiveForDownloading {
return Intl.message(
'Creating an archive for downloading',