TF-3517 Add integration test for case Save draft without Reply-To & reopen it
Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
@@ -10,6 +10,7 @@ import 'package:tmail_ui_user/features/composer/presentation/widgets/mobile/app_
|
||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/recipient_composer_widget.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/recipient_suggestion_item_widget.dart';
|
||||
import 'package:tmail_ui_user/features/composer/presentation/widgets/subject_composer_widget.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
import '../base/core_robot.dart';
|
||||
import '../extensions/patrol_finder_extension.dart';
|
||||
@@ -17,9 +18,12 @@ import '../extensions/patrol_finder_extension.dart';
|
||||
class ComposerRobot extends CoreRobot {
|
||||
ComposerRobot(super.$);
|
||||
|
||||
Future<void> addRecipient(String email) async {
|
||||
Future<void> addRecipientIntoField({
|
||||
required PrefixEmailAddress prefixEmailAddress,
|
||||
required String email,
|
||||
}) async {
|
||||
final finder = $(RecipientComposerWidget)
|
||||
.which<RecipientComposerWidget>((widget) => widget.prefix == PrefixEmailAddress.to);
|
||||
.which<RecipientComposerWidget>((widget) => widget.prefix == prefixEmailAddress);
|
||||
final isTextFieldFocused = finder
|
||||
.which<RecipientComposerWidget>((view) => view.focusNode?.hasFocus ?? false)
|
||||
.exists;
|
||||
@@ -58,10 +62,10 @@ class ComposerRobot extends CoreRobot {
|
||||
await composerController!.htmlEditorApi!.insertHtml('$content <br><br>');
|
||||
}
|
||||
|
||||
Future<void> sendEmail() async {
|
||||
Future<void> sendEmail(ImagePaths imagePaths) async {
|
||||
await $(AppBarComposerWidget)
|
||||
.$(TMailButtonWidget)
|
||||
.which<TMailButtonWidget>((widget) => widget.icon == ImagePaths().icSendMobile)
|
||||
.which<TMailButtonWidget>((widget) => widget.icon == imagePaths.icSendMobile)
|
||||
.tap();
|
||||
}
|
||||
|
||||
@@ -70,4 +74,15 @@ class ComposerRobot extends CoreRobot {
|
||||
await $.native.grantPermissionWhenInUse();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> tapCloseComposer(ImagePaths imagePaths) async {
|
||||
await $(AppBarComposerWidget)
|
||||
.$(TMailButtonWidget)
|
||||
.which<TMailButtonWidget>((widget) => widget.icon == imagePaths.icCancel)
|
||||
.tap();
|
||||
}
|
||||
|
||||
Future<void> tapSaveButtonOnSaveDraftConfirmDialog(AppLocalizations appLocalizations) async {
|
||||
await $(find.text(appLocalizations.save)).tap();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/label_mailbox_item_widget.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_item_widget.dart';
|
||||
|
||||
import '../base/core_robot.dart';
|
||||
|
||||
class MailboxMenuRobot extends CoreRobot {
|
||||
@@ -7,4 +11,11 @@ class MailboxMenuRobot extends CoreRobot {
|
||||
Future<void> openAppGrid() async {
|
||||
await $(#toggle_app_grid_button).tap();
|
||||
}
|
||||
|
||||
Future<void> openFolderByName(String name) async {
|
||||
await $(MailboxItemWidget)
|
||||
.$(LabelMailboxItemWidget)
|
||||
.$(find.text(name))
|
||||
.tap();
|
||||
}
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
import 'package:core/presentation/resources/image_paths.dart';
|
||||
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/features/mailbox/presentation/mailbox_view.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/label_mailbox_item_widget.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/mailbox_item_widget.dart';
|
||||
import 'package:tmail_ui_user/features/thread/presentation/widgets/email_tile_builder.dart';
|
||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||
|
||||
import '../base/base_test_scenario.dart';
|
||||
import '../robots/composer_robot.dart';
|
||||
import '../robots/mailbox_menu_robot.dart';
|
||||
import '../robots/thread_robot.dart';
|
||||
|
||||
class SaveDraftThenCloseComposerAndOpenDraftScenario extends BaseTestScenario {
|
||||
|
||||
const SaveDraftThenCloseComposerAndOpenDraftScenario(super.$);
|
||||
|
||||
@override
|
||||
Future<void> runTestLogic() async {
|
||||
const email = String.fromEnvironment('BASIC_AUTH_EMAIL');
|
||||
const subject = 'Save draft email without Reply-To';
|
||||
|
||||
final threadRobot = ThreadRobot($);
|
||||
final composerRobot = ComposerRobot($);
|
||||
final mailboxMenuRobot = MailboxMenuRobot($);
|
||||
final appLocalizations = AppLocalizations();
|
||||
final imagePaths = ImagePaths();
|
||||
|
||||
await threadRobot.openComposer();
|
||||
await _expectComposerViewVisible();
|
||||
|
||||
await composerRobot.grantContactPermission();
|
||||
|
||||
await composerRobot.addRecipientIntoField(
|
||||
prefixEmailAddress: PrefixEmailAddress.to,
|
||||
email: email,
|
||||
);
|
||||
|
||||
await composerRobot.addSubject(subject);
|
||||
|
||||
await composerRobot.tapCloseComposer(imagePaths);
|
||||
await $.pump(const Duration(seconds: 2));
|
||||
await _expectSaveDraftConfirmDialogVisible();
|
||||
|
||||
await composerRobot.tapSaveButtonOnSaveDraftConfirmDialog(appLocalizations);
|
||||
await _expectSaveDraftEmailSuccessToast(appLocalizations);
|
||||
|
||||
await $.pump(const Duration(seconds: 2));
|
||||
|
||||
await threadRobot.openMailbox();
|
||||
await _expectMailboxViewVisible();
|
||||
await _expectDraftFolderVisible(appLocalizations);
|
||||
|
||||
await mailboxMenuRobot.openFolderByName(appLocalizations.draftsMailboxDisplayName);
|
||||
await $.pump(const Duration(seconds: 2));
|
||||
await _expectDraftEmailWithSubjectVisible(subject);
|
||||
|
||||
await threadRobot.openEmailWithSubject(subject);
|
||||
await _expectComposerViewVisible();
|
||||
|
||||
await composerRobot.grantContactPermission();
|
||||
await _expectMobileEditorViewVisible();
|
||||
|
||||
await _expectReplyToFiledInvisible();
|
||||
}
|
||||
|
||||
Future<void> _expectComposerViewVisible() => expectViewVisible($(ComposerView));
|
||||
|
||||
Future<void> _expectSaveDraftEmailSuccessToast(AppLocalizations appLocalizations) async {
|
||||
await expectViewVisible($(find.text(appLocalizations.drafts_saved)));
|
||||
}
|
||||
|
||||
Future<void> _expectSaveDraftConfirmDialogVisible() async {
|
||||
await expectViewVisible($(#confirm_dialog_action));
|
||||
}
|
||||
|
||||
Future<void> _expectMailboxViewVisible() => expectViewVisible($(MailboxView));
|
||||
|
||||
Future<void> _expectDraftFolderVisible(AppLocalizations appLocalizations) =>
|
||||
expectViewVisible(
|
||||
$(MailboxItemWidget)
|
||||
.$(LabelMailboxItemWidget)
|
||||
.$(find.text(appLocalizations.draftsMailboxDisplayName))
|
||||
);
|
||||
|
||||
Future<void> _expectDraftEmailWithSubjectVisible(String subject) async {
|
||||
await expectViewVisible($(EmailTileBuilder).$(find.text(subject)));
|
||||
}
|
||||
|
||||
Future<void> _expectMobileEditorViewVisible() async {
|
||||
await expectViewVisible($(#mobile_editor));
|
||||
}
|
||||
|
||||
Future<void> _expectReplyToFiledInvisible() async {
|
||||
expect(
|
||||
$(RecipientComposerWidget)
|
||||
.which<RecipientComposerWidget>((view) => view.prefix == PrefixEmailAddress.replyTo),
|
||||
findsNothing,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
import 'package:core/core.dart';
|
||||
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/main/localizations/app_localizations.dart';
|
||||
|
||||
@@ -18,17 +20,24 @@ class SendEmailScenario extends BaseTestScenario {
|
||||
|
||||
final threadRobot = ThreadRobot($);
|
||||
final composerRobot = ComposerRobot($);
|
||||
final imagePaths = ImagePaths();
|
||||
|
||||
await threadRobot.openComposer();
|
||||
await _expectComposerViewVisible();
|
||||
|
||||
await composerRobot.grantContactPermission();
|
||||
|
||||
await composerRobot.addRecipient(email);
|
||||
await composerRobot.addRecipient(additionalRecipient);
|
||||
await composerRobot.addRecipientIntoField(
|
||||
prefixEmailAddress: PrefixEmailAddress.to,
|
||||
email: email,
|
||||
);
|
||||
await composerRobot.addRecipientIntoField(
|
||||
prefixEmailAddress: PrefixEmailAddress.to,
|
||||
email: additionalRecipient,
|
||||
);
|
||||
await composerRobot.addSubject(subject);
|
||||
await composerRobot.addContent(content);
|
||||
await composerRobot.sendEmail();
|
||||
await composerRobot.sendEmail(imagePaths);
|
||||
|
||||
await _expectSendEmailSuccessToast();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import '../../base/test_base.dart';
|
||||
import '../../scenarios/save_draft_then_close_composer_and_open_draft_scenario.dart';
|
||||
|
||||
void main() {
|
||||
TestBase().runPatrolTest(
|
||||
description: 'Should not see email address in `Reply-To` field when save draft email without `Reply-To` then open draft email',
|
||||
scenarioBuilder: ($) => SaveDraftThenCloseComposerAndOpenDraftScenario($),
|
||||
);
|
||||
}
|
||||
@@ -13,6 +13,7 @@ mixin MessageDialogActionMixin {
|
||||
String message,
|
||||
String actionName,
|
||||
{
|
||||
Key key = const Key('confirm_dialog_action'),
|
||||
Function? onConfirmAction,
|
||||
Function? onCancelAction,
|
||||
OnCloseButtonAction? onCloseButtonAction,
|
||||
@@ -56,7 +57,7 @@ mixin MessageDialogActionMixin {
|
||||
titleActionButtonMaxLines: titleActionButtonMaxLines,
|
||||
isArrangeActionButtonsVertical: isArrangeActionButtonsVertical
|
||||
)
|
||||
..key(const Key('confirm_dialog_action'))
|
||||
..key(key)
|
||||
..title(title ?? '')
|
||||
..content(message)
|
||||
..addIcon(icon)
|
||||
@@ -108,7 +109,7 @@ mixin MessageDialogActionMixin {
|
||||
titleActionButtonMaxLines: titleActionButtonMaxLines,
|
||||
isArrangeActionButtonsVertical: isArrangeActionButtonsVertical
|
||||
)
|
||||
..key(const Key('confirm_dialog_action'))
|
||||
..key(key)
|
||||
..title(title ?? '')
|
||||
..content(message)
|
||||
..addIcon(icon)
|
||||
@@ -186,7 +187,7 @@ mixin MessageDialogActionMixin {
|
||||
titleActionButtonMaxLines: titleActionButtonMaxLines,
|
||||
isArrangeActionButtonsVertical: isArrangeActionButtonsVertical
|
||||
)
|
||||
..key(const Key('confirm_dialog_action'))
|
||||
..key(key)
|
||||
..title(title ?? '')
|
||||
..content(message)
|
||||
..addIcon(icon)
|
||||
|
||||
@@ -6,8 +6,8 @@ import 'package:tmail_ui_user/features/base/styles/popup_item_widget_style.dart'
|
||||
|
||||
class PopupItemWidget extends StatelessWidget {
|
||||
|
||||
final String _iconAction;
|
||||
final String _nameAction;
|
||||
final String iconAction;
|
||||
final String nameAction;
|
||||
final Color? colorIcon;
|
||||
final double? iconSize;
|
||||
final TextStyle? styleName;
|
||||
@@ -16,20 +16,18 @@ class PopupItemWidget extends StatelessWidget {
|
||||
final EdgeInsetsGeometry? padding;
|
||||
final VoidCallback? onCallbackAction;
|
||||
|
||||
const PopupItemWidget(
|
||||
this._iconAction,
|
||||
this._nameAction,
|
||||
{
|
||||
Key? key,
|
||||
this.colorIcon,
|
||||
this.iconSize,
|
||||
this.styleName,
|
||||
this.isSelected,
|
||||
this.padding,
|
||||
this.selectedIcon,
|
||||
this.onCallbackAction
|
||||
}
|
||||
) : super(key: key);
|
||||
const PopupItemWidget({
|
||||
Key? key,
|
||||
required this.iconAction,
|
||||
required this.nameAction,
|
||||
this.colorIcon,
|
||||
this.iconSize,
|
||||
this.styleName,
|
||||
this.isSelected,
|
||||
this.padding,
|
||||
this.selectedIcon,
|
||||
this.onCallbackAction,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -44,7 +42,7 @@ class PopupItemWidget extends StatelessWidget {
|
||||
padding: padding,
|
||||
child: Row(children: [
|
||||
SvgPicture.asset(
|
||||
_iconAction,
|
||||
iconAction,
|
||||
width: iconSize ?? PopupItemWidgetStyle.iconSize,
|
||||
height: iconSize ?? PopupItemWidgetStyle.iconSize,
|
||||
fit: BoxFit.fill,
|
||||
@@ -52,7 +50,7 @@ class PopupItemWidget extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(width: PopupItemWidgetStyle.space),
|
||||
Expanded(child: Text(
|
||||
_nameAction,
|
||||
nameAction,
|
||||
style: styleName ?? PopupItemWidgetStyle.labelTextStyle
|
||||
)),
|
||||
if (isSelected == true && selectedIcon != null)
|
||||
|
||||
@@ -496,8 +496,8 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
PopupMenuItem(
|
||||
padding: EdgeInsets.zero,
|
||||
child: PopupItemWidget(
|
||||
controller.imagePaths.icReadReceipt,
|
||||
AppLocalizations.of(context).requestReadReceipt,
|
||||
iconAction: controller.imagePaths.icReadReceipt,
|
||||
nameAction: AppLocalizations.of(context).requestReadReceipt,
|
||||
styleName: ComposerStyle.popupItemTextStyle,
|
||||
padding: ComposerStyle.popupItemPadding,
|
||||
colorIcon: ComposerStyle.popupItemIconColor,
|
||||
@@ -512,8 +512,8 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
PopupMenuItem(
|
||||
padding: EdgeInsets.zero,
|
||||
child: PopupItemWidget(
|
||||
controller.imagePaths.icSaveToDraft,
|
||||
AppLocalizations.of(context).saveAsDraft,
|
||||
iconAction: controller.imagePaths.icSaveToDraft,
|
||||
nameAction: AppLocalizations.of(context).saveAsDraft,
|
||||
colorIcon: ComposerStyle.popupItemIconColor,
|
||||
styleName: ComposerStyle.popupItemTextStyle,
|
||||
padding: ComposerStyle.popupItemPadding,
|
||||
@@ -526,8 +526,8 @@ class ComposerView extends GetWidget<ComposerController> {
|
||||
PopupMenuItem(
|
||||
padding: EdgeInsets.zero,
|
||||
child: PopupItemWidget(
|
||||
controller.imagePaths.icDeleteMailbox,
|
||||
AppLocalizations.of(context).delete,
|
||||
iconAction: controller.imagePaths.icDeleteMailbox,
|
||||
nameAction: AppLocalizations.of(context).delete,
|
||||
styleName: ComposerStyle.popupItemTextStyle,
|
||||
padding: ComposerStyle.popupItemPadding,
|
||||
onCallbackAction: () {
|
||||
|
||||
@@ -104,8 +104,8 @@ class BottomBarComposerWidget extends StatelessWidget {
|
||||
),
|
||||
listButtonAction: [
|
||||
PopupItemWidget(
|
||||
imagePaths.icStyleCodeView,
|
||||
AppLocalizations.of(context).embedCode,
|
||||
iconAction: imagePaths.icStyleCodeView,
|
||||
nameAction: AppLocalizations.of(context).embedCode,
|
||||
styleName: BottomBarComposerWidgetStyle.popupItemTextStyle,
|
||||
colorIcon: BottomBarComposerWidgetStyle.iconColor,
|
||||
padding: BottomBarComposerWidgetStyle.popupItemPadding,
|
||||
@@ -117,8 +117,8 @@ class BottomBarComposerWidget extends StatelessWidget {
|
||||
},
|
||||
),
|
||||
PopupItemWidget(
|
||||
imagePaths.icReadReceipt,
|
||||
AppLocalizations.of(context).requestReadReceipt,
|
||||
iconAction: imagePaths.icReadReceipt,
|
||||
nameAction: AppLocalizations.of(context).requestReadReceipt,
|
||||
styleName: BottomBarComposerWidgetStyle.popupItemTextStyle,
|
||||
padding: BottomBarComposerWidgetStyle.popupItemPadding,
|
||||
colorIcon: BottomBarComposerWidgetStyle.iconColor,
|
||||
@@ -131,8 +131,8 @@ class BottomBarComposerWidget extends StatelessWidget {
|
||||
),
|
||||
if (_isPrintEnabled)
|
||||
PopupItemWidget(
|
||||
imagePaths.icPrinter,
|
||||
AppLocalizations.of(context).print,
|
||||
iconAction: imagePaths.icPrinter,
|
||||
nameAction: AppLocalizations.of(context).print,
|
||||
colorIcon: BottomBarComposerWidgetStyle.iconColor,
|
||||
styleName: BottomBarComposerWidgetStyle.popupItemTextStyle,
|
||||
padding: BottomBarComposerWidgetStyle.popupItemPadding,
|
||||
|
||||
+10
-10
@@ -121,8 +121,8 @@ class MobileResponsiveAppBarComposerWidget extends StatelessWidget {
|
||||
),
|
||||
listButtonAction: [
|
||||
PopupItemWidget(
|
||||
imagePaths.icStyleCodeView,
|
||||
AppLocalizations.of(context).embedCode,
|
||||
iconAction: imagePaths.icStyleCodeView,
|
||||
nameAction: AppLocalizations.of(context).embedCode,
|
||||
styleName: MobileAppBarComposerWidgetStyle.popupItemTextStyle,
|
||||
colorIcon: MobileAppBarComposerWidgetStyle.iconColor,
|
||||
padding: MobileAppBarComposerWidgetStyle.popupItemPadding,
|
||||
@@ -134,8 +134,8 @@ class MobileResponsiveAppBarComposerWidget extends StatelessWidget {
|
||||
},
|
||||
),
|
||||
PopupItemWidget(
|
||||
imagePaths.icReadReceipt,
|
||||
AppLocalizations.of(context).requestReadReceipt,
|
||||
iconAction: imagePaths.icReadReceipt,
|
||||
nameAction: AppLocalizations.of(context).requestReadReceipt,
|
||||
styleName: MobileAppBarComposerWidgetStyle.popupItemTextStyle,
|
||||
padding: MobileAppBarComposerWidgetStyle.popupItemPadding,
|
||||
colorIcon: MobileAppBarComposerWidgetStyle.popupItemIconColor,
|
||||
@@ -148,8 +148,8 @@ class MobileResponsiveAppBarComposerWidget extends StatelessWidget {
|
||||
),
|
||||
if (_isPrintEnabled)
|
||||
PopupItemWidget(
|
||||
imagePaths.icPrinter,
|
||||
AppLocalizations.of(context).print,
|
||||
iconAction: imagePaths.icPrinter,
|
||||
nameAction: AppLocalizations.of(context).print,
|
||||
colorIcon: MobileAppBarComposerWidgetStyle.popupItemIconColor,
|
||||
styleName: MobileAppBarComposerWidgetStyle.popupItemTextStyle,
|
||||
padding: MobileAppBarComposerWidgetStyle.popupItemPadding,
|
||||
@@ -159,8 +159,8 @@ class MobileResponsiveAppBarComposerWidget extends StatelessWidget {
|
||||
},
|
||||
),
|
||||
PopupItemWidget(
|
||||
imagePaths.icSaveToDraft,
|
||||
AppLocalizations.of(context).saveAsDraft,
|
||||
iconAction: imagePaths.icSaveToDraft,
|
||||
nameAction: AppLocalizations.of(context).saveAsDraft,
|
||||
colorIcon: MobileAppBarComposerWidgetStyle.popupItemIconColor,
|
||||
styleName: MobileAppBarComposerWidgetStyle.popupItemTextStyle,
|
||||
padding: MobileAppBarComposerWidgetStyle.popupItemPadding,
|
||||
@@ -170,8 +170,8 @@ class MobileResponsiveAppBarComposerWidget extends StatelessWidget {
|
||||
},
|
||||
),
|
||||
PopupItemWidget(
|
||||
imagePaths.icDeleteMailbox,
|
||||
AppLocalizations.of(context).delete,
|
||||
iconAction: imagePaths.icDeleteMailbox,
|
||||
nameAction: AppLocalizations.of(context).delete,
|
||||
colorIcon: MobileAppBarComposerWidgetStyle.popupItemIconColor,
|
||||
styleName: MobileAppBarComposerWidgetStyle.popupItemTextStyle,
|
||||
padding: MobileAppBarComposerWidgetStyle.popupItemPadding,
|
||||
|
||||
@@ -565,8 +565,8 @@ class EmailView extends GetWidget<SingleEmailController> {
|
||||
key: Key('${action.name}_action'),
|
||||
padding: EdgeInsets.zero,
|
||||
child: PopupItemWidget(
|
||||
action.getIcon(controller.imagePaths),
|
||||
action.getTitle(context),
|
||||
iconAction: action.getIcon(controller.imagePaths),
|
||||
nameAction: action.getTitle(context),
|
||||
colorIcon: AppColor.colorTextButton,
|
||||
padding: const EdgeInsetsDirectional.only(start: 12),
|
||||
styleName: const TextStyle(
|
||||
|
||||
@@ -315,8 +315,8 @@ mixin MailboxWidgetMixin {
|
||||
child: Opacity(
|
||||
opacity: contextMenuItem.isActivated ? 1.0 : 0.3,
|
||||
child: PopupItemWidget(
|
||||
contextMenuItem.action.getContextMenuIcon(imagePaths),
|
||||
contextMenuItem.action.getTitleContextMenu(context),
|
||||
iconAction: contextMenuItem.action.getContextMenuIcon(imagePaths),
|
||||
nameAction: contextMenuItem.action.getTitleContextMenu(context),
|
||||
colorIcon: contextMenuItem.action.getColorContextMenuIcon(),
|
||||
padding: const EdgeInsetsDirectional.only(start: 12),
|
||||
iconSize: 24,
|
||||
|
||||
Reference in New Issue
Block a user