E2E Fix integration test Twake Mail v0.18.4
E2E Fix integration test Twake Mail v0.18.4
This commit is contained in:
@@ -19,7 +19,7 @@ class TestBase {
|
|||||||
description,
|
description,
|
||||||
config: const PatrolTesterConfig(
|
config: const PatrolTesterConfig(
|
||||||
settlePolicy: SettlePolicy.trySettle,
|
settlePolicy: SettlePolicy.trySettle,
|
||||||
visibleTimeout: Duration(minutes: 1),
|
visibleTimeout: Duration(seconds: 30),
|
||||||
printLogs: true,
|
printLogs: true,
|
||||||
),
|
),
|
||||||
nativeAutomatorConfig: const NativeAutomatorConfig(
|
nativeAutomatorConfig: const NativeAutomatorConfig(
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'dart:io' hide HttpClient;
|
|||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:core/utils/app_logger.dart';
|
import 'package:core/utils/app_logger.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:jmap_dart_client/http/http_client.dart';
|
import 'package:jmap_dart_client/http/http_client.dart';
|
||||||
import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart';
|
import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart';
|
||||||
@@ -270,4 +271,8 @@ mixin ScenarioUtilsMixin {
|
|||||||
|
|
||||||
IdentityInteractorsBindings().dispose();
|
IdentityInteractorsBindings().dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> hideKeyboard() async {
|
||||||
|
await SystemChannels.textInput.invokeMethod('TextInput.hide');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import 'package:model/extensions/session_extension.dart';
|
|||||||
import 'package:model/upload/file_info.dart';
|
import 'package:model/upload/file_info.dart';
|
||||||
import 'package:rich_text_composer/rich_text_composer.dart';
|
import 'package:rich_text_composer/rich_text_composer.dart';
|
||||||
import 'package:tmail_ui_user/features/base/widget/popup_item_widget.dart';
|
import 'package:tmail_ui_user/features/base/widget/popup_item_widget.dart';
|
||||||
|
import 'package:tmail_ui_user/features/composer/domain/state/download_image_as_base64_state.dart';
|
||||||
import 'package:tmail_ui_user/features/composer/presentation/composer_controller.dart';
|
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/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/view/mobile/mobile_editor_view.dart';
|
||||||
@@ -33,13 +34,6 @@ class ComposerRobot extends CoreRobot {
|
|||||||
}) async {
|
}) async {
|
||||||
final finder = $(RecipientComposerWidget).which<RecipientComposerWidget>(
|
final finder = $(RecipientComposerWidget).which<RecipientComposerWidget>(
|
||||||
(widget) => widget.prefix == prefixEmailAddress);
|
(widget) => widget.prefix == prefixEmailAddress);
|
||||||
final isTextFieldFocused = finder
|
|
||||||
.which<RecipientComposerWidget>(
|
|
||||||
(view) => view.focusNode?.hasFocus ?? false)
|
|
||||||
.exists;
|
|
||||||
if (!isTextFieldFocused) {
|
|
||||||
await finder.tap();
|
|
||||||
}
|
|
||||||
await finder.enterTextWithoutTapAction(email);
|
await finder.enterTextWithoutTapAction(email);
|
||||||
|
|
||||||
await $(RecipientSuggestionItemWidget)
|
await $(RecipientSuggestionItemWidget)
|
||||||
@@ -163,6 +157,10 @@ class ComposerRobot extends CoreRobot {
|
|||||||
fileSize: await file.length(),
|
fileSize: await file.length(),
|
||||||
fileName: file.path.split('/').last,
|
fileName: file.path.split('/').last,
|
||||||
)));
|
)));
|
||||||
|
await controller.viewState.stream.firstWhere((state) => state.fold(
|
||||||
|
(failure) => false,
|
||||||
|
(success) => success is DownloadImageAsBase64Success,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> toggleReadReceipt() async {
|
Future<void> toggleReadReceipt() async {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class EmailAddressDialogRobot extends CoreRobot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> tapCopyEmailAddressButton(AppLocalizations appLocalizations) async {
|
Future<void> tapCopyEmailAddressButton(AppLocalizations appLocalizations) async {
|
||||||
await $(appLocalizations.copy_email_address).tap();
|
await $(#copy_email_address).tap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> tapComposeEmailButton(AppLocalizations appLocalizations) async {
|
Future<void> tapComposeEmailButton(AppLocalizations appLocalizations) async {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import 'package:core/presentation/views/button/tmail_button_widget.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:tmail_ui_user/features/base/widget/material_text_button.dart';
|
|
||||||
import 'package:tmail_ui_user/features/email/presentation/widgets/email_view_back_button.dart';
|
import 'package:tmail_ui_user/features/email/presentation/widgets/email_view_back_button.dart';
|
||||||
|
import 'package:tmail_ui_user/features/email/presentation/widgets/information_sender_and_receiver_builder.dart';
|
||||||
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
|
||||||
|
|
||||||
import '../base/core_robot.dart';
|
import '../base/core_robot.dart';
|
||||||
@@ -40,47 +39,42 @@ class EmailRobot extends CoreRobot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> tapMarkAsUnreadOptionInContextMenu() async {
|
Future<void> tapMarkAsUnreadOptionInContextMenu() async {
|
||||||
await $(#markAsUnread_action).tap();
|
await $(AppLocalizations().mark_as_unread).tap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> tapEmailDetailedStarButton() async {
|
Future<void> tapEmailDetailedStarButton() async {
|
||||||
await $(#email_detailed_star_button).tap();
|
await $(AppLocalizations().starred).tap();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> tapEmailDetailedUnstarButton() async {
|
||||||
|
await $(AppLocalizations().not_starred).tap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> tapEmailDetailedMoveEmailButton() async {
|
Future<void> tapEmailDetailedMoveEmailButton() async {
|
||||||
await $(#email_detailed_move_email_button).tap();
|
await $(AppLocalizations().moveMessage).tap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> tapEmailDetailedDeleteEmailButton() async {
|
Future<void> tapEmailDetailedDeleteEmailButton() async {
|
||||||
await $(#email_detailed_delete_email_button).tap();
|
await $(AppLocalizations().move_to_trash).tap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> tapMarkAsSpamOptionInContextMenu() async {
|
Future<void> tapMarkAsSpamOptionInContextMenu() async {
|
||||||
await $(#moveToSpam_action).tap();
|
await $(AppLocalizations().markAsSpam).tap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> tapArchiveMessageOptionInContextMenu() async {
|
Future<void> tapArchiveMessageOptionInContextMenu() async {
|
||||||
await $(#archiveMessage_action).tap();
|
await $(AppLocalizations().archiveMessage).tap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> tapSenderEmailAddress(String email) async {
|
Future<void> tapSenderEmailAddress(String email) async {
|
||||||
await $(MaterialTextButton)
|
await $(InformationSenderAndReceiverBuilder).$(email).tap();
|
||||||
.which<MaterialTextButton>((widget) => widget.label.contains(email))
|
|
||||||
.first
|
|
||||||
.tap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> tapRecipientEmailAddress(String email) async {
|
Future<void> tapRecipientEmailAddress(String email) async {
|
||||||
await $(TMailButtonWidget)
|
await $(InformationSenderAndReceiverBuilder).$(email).tap();
|
||||||
.which<TMailButtonWidget>((widget) => widget.text.contains(email))
|
|
||||||
.first
|
|
||||||
.tap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> longPressSenderEmailAddress(String email) async {
|
Future<void> longPressSenderEmailAddress(String email) async {
|
||||||
await $(MaterialTextButton)
|
await $(InformationSenderAndReceiverBuilder).$(email).longPress();
|
||||||
.which<MaterialTextButton>((widget) => widget.label.contains(email))
|
|
||||||
.first
|
|
||||||
.longPress();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
import 'package:core/presentation/resources/image_paths.dart';
|
import 'package:core/presentation/resources/image_paths.dart';
|
||||||
import 'package:core/presentation/views/button/tmail_button_widget.dart';
|
import 'package:core/presentation/views/button/tmail_button_widget.dart';
|
||||||
import 'package:core/presentation/views/text/text_field_builder.dart';
|
import 'package:core/presentation/views/text/text_field_builder.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/label_mailbox_item_widget.dart';
|
import 'package:tmail_ui_user/features/mailbox/presentation/widgets/label_mailbox_item_widget.dart';
|
||||||
@@ -71,11 +70,7 @@ class MailboxMenuRobot extends CoreRobot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> closeMenu() async {
|
Future<void> closeMenu() async {
|
||||||
await $(IconButton)
|
await $.native.swipe(from: const Offset(0.9, 0.5), to: const Offset(0, 0.5));
|
||||||
.which<IconButton>((widget) {
|
|
||||||
return widget.tooltip == AppLocalizations().close;
|
|
||||||
})
|
|
||||||
.tap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int getCurrentInboxCount() {
|
int getCurrentInboxCount() {
|
||||||
|
|||||||
@@ -57,14 +57,14 @@ class ThreadRobot extends CoreRobot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> selectAttachmentFilter() async {
|
Future<void> selectAttachmentFilter() async {
|
||||||
await $(#filter_email_attachments).tap();
|
await $(#attachments_filter).tap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> selectUnreadFilter() async {
|
Future<void> selectUnreadFilter() async {
|
||||||
await $(#filter_email_unread).tap();
|
await $(#unread_filter).tap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> selectStarredFilter() async {
|
Future<void> selectStarredFilter() async {
|
||||||
await $(#filter_email_starred).tap();
|
await $(#starred_filter).tap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+8
-9
@@ -27,10 +27,11 @@ class ComposerUploadAttachmentAndInlineImageScenario extends BaseTestScenario {
|
|||||||
final png = await preparingPngWithName(pngName);
|
final png = await preparingPngWithName(pngName);
|
||||||
|
|
||||||
await composerRobot.addAttachment(png);
|
await composerRobot.addAttachment(png);
|
||||||
|
await $.pumpAndSettle();
|
||||||
|
await _expectAttachment(pngName);
|
||||||
|
|
||||||
await composerRobot.addInline(png);
|
await composerRobot.addInline(png);
|
||||||
await $.pumpAndSettle();
|
await $.pumpAndSettle();
|
||||||
|
|
||||||
_expectAttachment(pngName);
|
|
||||||
await _expectInline();
|
await _expectInline();
|
||||||
|
|
||||||
await composerRobot.addAttachment(png);
|
await composerRobot.addAttachment(png);
|
||||||
@@ -50,13 +51,11 @@ class ComposerUploadAttachmentAndInlineImageScenario extends BaseTestScenario {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _expectAttachment(String pngName) {
|
Future<void> _expectAttachment(String pngName) async {
|
||||||
return expect(
|
await expectViewVisible(
|
||||||
$(AttachmentItemComposerWidget)
|
$(AttachmentItemComposerWidget).which<AttachmentItemComposerWidget>(
|
||||||
.which<AttachmentItemComposerWidget>(
|
(widget) => widget.fileName.contains(pngName),
|
||||||
(widget) => widget.fileName.contains(pngName)
|
),
|
||||||
),
|
|
||||||
findsOneWidget,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,10 +38,10 @@ class ArchiveEmailScenario extends BaseTestScenario {
|
|||||||
_expectEmailDetailedMoreButtonVisible();
|
_expectEmailDetailedMoreButtonVisible();
|
||||||
|
|
||||||
await emailRobot.tapEmailDetailedMoreButton();
|
await emailRobot.tapEmailDetailedMoreButton();
|
||||||
await $.pumpAndSettle(duration: const Duration(seconds: 2));
|
await $.pumpAndSettle(duration: const Duration(seconds: 1));
|
||||||
|
|
||||||
await emailRobot.tapArchiveMessageOptionInContextMenu();
|
await emailRobot.tapArchiveMessageOptionInContextMenu();
|
||||||
await $.pumpAndSettle(duration: const Duration(seconds: 3));
|
await $.pumpAndSettle(duration: const Duration(seconds: 1));
|
||||||
|
|
||||||
await emailRobot.onTapBackButton();
|
await emailRobot.onTapBackButton();
|
||||||
await $.pumpAndSettle();
|
await $.pumpAndSettle();
|
||||||
|
|||||||
@@ -37,8 +37,9 @@ class DeleteEmailScenario extends BaseTestScenario {
|
|||||||
await threadRobot.openEmailWithSubject(subject);
|
await threadRobot.openEmailWithSubject(subject);
|
||||||
await $.pumpAndSettle();
|
await $.pumpAndSettle();
|
||||||
|
|
||||||
|
await emailRobot.tapEmailDetailedMoreButton();
|
||||||
await emailRobot.tapEmailDetailedDeleteEmailButton();
|
await emailRobot.tapEmailDetailedDeleteEmailButton();
|
||||||
await $.pumpAndSettle(duration: const Duration(seconds: 3));
|
await $.pumpAndSettle(duration: const Duration(seconds: 1));
|
||||||
|
|
||||||
_expectEmailViewInvisible();
|
_expectEmailViewInvisible();
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -52,7 +52,7 @@ class DisplayEmailAddressInfoDialogScenario extends BaseTestScenario {
|
|||||||
Future<void> _expectEmailAddressInfoDialogVisible(
|
Future<void> _expectEmailAddressInfoDialogVisible(
|
||||||
AppLocalizations appLocalizations,
|
AppLocalizations appLocalizations,
|
||||||
) async {
|
) async {
|
||||||
await expectViewVisible($(appLocalizations.copy_email_address));
|
await expectViewVisible($(#copy_email_address));
|
||||||
await expectViewVisible($(appLocalizations.quickCreatingRule));
|
await expectViewVisible($(appLocalizations.quickCreatingRule));
|
||||||
await expectViewVisible($(appLocalizations.compose_email));
|
await expectViewVisible($(appLocalizations.compose_email));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
|
|
||||||
import 'package:core/presentation/resources/image_paths.dart';
|
|
||||||
import 'package:core/presentation/views/button/tmail_button_widget.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
import '../../base/base_test_scenario.dart';
|
import '../../base/base_test_scenario.dart';
|
||||||
@@ -18,7 +15,6 @@ class MarkAsStarEmailScenario extends BaseTestScenario {
|
|||||||
const emailUser = String.fromEnvironment('BASIC_AUTH_EMAIL');
|
const emailUser = String.fromEnvironment('BASIC_AUTH_EMAIL');
|
||||||
final threadRobot = ThreadRobot($);
|
final threadRobot = ThreadRobot($);
|
||||||
final emailRobot = EmailRobot($);
|
final emailRobot = EmailRobot($);
|
||||||
final imagePaths = ImagePaths();
|
|
||||||
|
|
||||||
await provisionEmail(
|
await provisionEmail(
|
||||||
[
|
[
|
||||||
@@ -34,32 +30,29 @@ class MarkAsStarEmailScenario extends BaseTestScenario {
|
|||||||
|
|
||||||
await threadRobot.openEmailWithSubject(subject);
|
await threadRobot.openEmailWithSubject(subject);
|
||||||
await $.pumpAndSettle();
|
await $.pumpAndSettle();
|
||||||
_expectEmailDetailedStarButtonVisible();
|
await emailRobot.tapEmailDetailedMoreButton();
|
||||||
|
await _expectEmailDetailedStarButtonVisible();
|
||||||
|
|
||||||
await emailRobot.tapEmailDetailedStarButton();
|
await emailRobot.tapEmailDetailedStarButton();
|
||||||
await $.pumpAndSettle(duration: const Duration(seconds: 2));
|
await $.pumpAndSettle(duration: const Duration(seconds: 1));
|
||||||
await _expectDisplayedStarIcon(imagePaths);
|
await emailRobot.tapEmailDetailedMoreButton();
|
||||||
|
await _expectDisplayedUnStarIcon();
|
||||||
|
|
||||||
await emailRobot.tapEmailDetailedStarButton();
|
await emailRobot.tapEmailDetailedUnstarButton();
|
||||||
await $.pumpAndSettle(duration: const Duration(seconds: 2));
|
await $.pumpAndSettle(duration: const Duration(seconds: 1));
|
||||||
await _expectDisplayedUnStarIcon(imagePaths);
|
await emailRobot.tapEmailDetailedMoreButton();
|
||||||
|
await _expectDisplayedStarIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _expectEmailDetailedStarButtonVisible() {
|
Future<void> _expectEmailDetailedStarButtonVisible() async {
|
||||||
expect($(#email_detailed_star_button), findsOneWidget);
|
await expectViewVisible($(#markAsStarred_action));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _expectDisplayedStarIcon(ImagePaths imagePaths) async {
|
Future<void> _expectDisplayedStarIcon() async {
|
||||||
await expectViewVisible(
|
await expectViewVisible($(#markAsStarred_action));
|
||||||
$(#email_detailed_star_button).which<TMailButtonWidget>(
|
|
||||||
(widget) => widget.icon == imagePaths.icStar),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _expectDisplayedUnStarIcon(ImagePaths imagePaths) async {
|
Future<void> _expectDisplayedUnStarIcon() async {
|
||||||
await expectViewVisible(
|
await expectViewVisible($(#unMarkAsStarred_action));
|
||||||
$(#email_detailed_star_button).which<TMailButtonWidget>(
|
|
||||||
(widget) => widget.icon == imagePaths.icUnStar),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,6 +38,7 @@ class MoveEmailToFolderScenario extends BaseTestScenario {
|
|||||||
await threadRobot.openEmailWithSubject(subject);
|
await threadRobot.openEmailWithSubject(subject);
|
||||||
await $.pumpAndSettle();
|
await $.pumpAndSettle();
|
||||||
|
|
||||||
|
await emailRobot.tapEmailDetailedMoreButton();
|
||||||
await emailRobot.tapEmailDetailedMoveEmailButton();
|
await emailRobot.tapEmailDetailedMoveEmailButton();
|
||||||
await $.pumpAndSettle(duration: const Duration(seconds: 2));
|
await $.pumpAndSettle(duration: const Duration(seconds: 2));
|
||||||
|
|
||||||
|
|||||||
@@ -79,12 +79,15 @@ class ReplyEmailWithReplyToScenario extends BaseTestScenario {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _expectToFieldContainReplyToEmailAddress() async {
|
Future<void> _expectToFieldContainReplyToEmailAddress() async {
|
||||||
expect(
|
await expectViewVisible(
|
||||||
$(RecipientComposerWidget).which<RecipientComposerWidget>((widget) =>
|
$(RecipientComposerWidget).which<RecipientComposerWidget>(
|
||||||
widget.prefix == PrefixEmailAddress.to &&
|
(widget) =>
|
||||||
isMatchingEmailList(widget.listEmailAddress, {'emma-reply-to@example.com'})
|
widget.prefix == PrefixEmailAddress.to &&
|
||||||
).visible,
|
isMatchingEmailList(
|
||||||
isTrue,
|
widget.listEmailAddress,
|
||||||
|
{'emma-reply-to@example.com'},
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@ import '../robots/thread_robot.dart';
|
|||||||
|
|
||||||
class ForwardEmailScenario extends BaseTestScenario {
|
class ForwardEmailScenario extends BaseTestScenario {
|
||||||
|
|
||||||
static const String queryString = 'Fwd: Forward email to Bob';
|
static const String queryString = 'Forward email';
|
||||||
|
|
||||||
const ForwardEmailScenario(super.$);
|
const ForwardEmailScenario(super.$);
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class SaveAsTemplateScenario extends BaseTestScenario {
|
|||||||
await _expectSaveToastSuccessVisible();
|
await _expectSaveToastSuccessVisible();
|
||||||
|
|
||||||
await composerRobot.addSubject('test subject');
|
await composerRobot.addSubject('test subject');
|
||||||
|
await hideKeyboard();
|
||||||
await composerRobot.saveAsTemplate();
|
await composerRobot.saveAsTemplate();
|
||||||
|
|
||||||
await _expectUpdateToastSuccessVisible();
|
await _expectUpdateToastSuccessVisible();
|
||||||
|
|||||||
+10
-7
@@ -42,12 +42,15 @@ class ThreadDetailReplyRealTimeUpdateScenario extends BaseTestScenario {
|
|||||||
await composerRobot.grantContactPermission();
|
await composerRobot.grantContactPermission();
|
||||||
await composerRobot.addContent(replyContent);
|
await composerRobot.addContent(replyContent);
|
||||||
await composerRobot.sendEmail(imagePaths);
|
await composerRobot.sendEmail(imagePaths);
|
||||||
await $.waitUntilVisible($(ThreadDetailCollapsedEmail));
|
|
||||||
expect(
|
await _expectNewCollapsedEmail(replyContent);
|
||||||
$(ThreadDetailCollapsedEmail).which<ThreadDetailCollapsedEmail>((widget) {
|
}
|
||||||
return widget.preview.contains(replyContent);
|
|
||||||
}),
|
Future<void> _expectNewCollapsedEmail(String replyContent) async {
|
||||||
findsOneWidget,
|
final collapsedEmail = $(ThreadDetailCollapsedEmail)
|
||||||
);
|
.which<ThreadDetailCollapsedEmail>((widget) {
|
||||||
|
return widget.preview.contains(replyContent);
|
||||||
|
});
|
||||||
|
await expectViewVisible(collapsedEmail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -18,6 +18,7 @@ class ContextMenuDialogView extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: actions.map((menuAction) => ContextMenuDialogItem(
|
children: actions.map((menuAction) => ContextMenuDialogItem(
|
||||||
|
key: menuAction.key != null ? Key(menuAction.key!) : null,
|
||||||
menuAction: menuAction,
|
menuAction: menuAction,
|
||||||
onContextMenuActionClick: onContextMenuActionClick,
|
onContextMenuActionClick: onContextMenuActionClick,
|
||||||
)).toList(),
|
)).toList(),
|
||||||
|
|||||||
@@ -6,11 +6,12 @@ typedef OnContextMenuActionClick = void Function(ContextMenuItemAction action);
|
|||||||
|
|
||||||
abstract class ContextMenuItemAction<T> with EquatableMixin {
|
abstract class ContextMenuItemAction<T> with EquatableMixin {
|
||||||
final T action;
|
final T action;
|
||||||
|
final String? key;
|
||||||
|
|
||||||
ContextMenuItemAction(this.action);
|
ContextMenuItemAction(this.action, {this.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [action];
|
List<Object?> get props => [action, key];
|
||||||
|
|
||||||
String get actionName;
|
String get actionName;
|
||||||
|
|
||||||
@@ -33,7 +34,7 @@ mixin OptionalSelectedIcon<T> {
|
|||||||
|
|
||||||
abstract class ContextMenuItemActionRequiredIcon<T>
|
abstract class ContextMenuItemActionRequiredIcon<T>
|
||||||
extends ContextMenuItemAction<T> with OptionalIcon {
|
extends ContextMenuItemAction<T> with OptionalIcon {
|
||||||
ContextMenuItemActionRequiredIcon(super.action);
|
ContextMenuItemActionRequiredIcon(super.action, {super.key});
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class ContextMenuItemActionRequiredSelectedIcon<T>
|
abstract class ContextMenuItemActionRequiredSelectedIcon<T>
|
||||||
@@ -41,12 +42,12 @@ abstract class ContextMenuItemActionRequiredSelectedIcon<T>
|
|||||||
|
|
||||||
final T? selectedAction;
|
final T? selectedAction;
|
||||||
|
|
||||||
ContextMenuItemActionRequiredSelectedIcon(super.action, this.selectedAction);
|
ContextMenuItemActionRequiredSelectedIcon(super.action, this.selectedAction, {super.key});
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class ContextMenuItemActionRequiredFull<T>
|
abstract class ContextMenuItemActionRequiredFull<T>
|
||||||
extends ContextMenuItemAction<T> with OptionalIcon, OptionalSelectedIcon<T> {
|
extends ContextMenuItemAction<T> with OptionalIcon, OptionalSelectedIcon<T> {
|
||||||
final T selectedAction;
|
final T selectedAction;
|
||||||
|
|
||||||
ContextMenuItemActionRequiredFull(super.action, this.selectedAction);
|
ContextMenuItemActionRequiredFull(super.action, this.selectedAction, {super.key});
|
||||||
}
|
}
|
||||||
@@ -37,6 +37,7 @@ class EmailAddressWithCopyWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
if (label.isNotEmpty)
|
if (label.isNotEmpty)
|
||||||
TMailButtonWidget.fromIcon(
|
TMailButtonWidget.fromIcon(
|
||||||
|
key: const ValueKey('copy_email_address'),
|
||||||
icon: copyLabelIcon,
|
icon: copyLabelIcon,
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
iconSize: 20,
|
iconSize: 20,
|
||||||
|
|||||||
@@ -13,8 +13,9 @@ class ContextItemEmailAction
|
|||||||
ContextItemEmailAction(
|
ContextItemEmailAction(
|
||||||
super.action,
|
super.action,
|
||||||
this.appLocalizations,
|
this.appLocalizations,
|
||||||
this.imagePaths,
|
this.imagePaths, {
|
||||||
);
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get actionIcon => action.getIcon(imagePaths);
|
String get actionIcon => action.getIcon(imagePaths);
|
||||||
|
|||||||
@@ -591,6 +591,7 @@ class EmailActionReactor {
|
|||||||
action,
|
action,
|
||||||
AppLocalizations.of(currentContext!),
|
AppLocalizations.of(currentContext!),
|
||||||
imagePaths,
|
imagePaths,
|
||||||
|
key: '${action.name}_action',
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
|
|||||||
@@ -162,7 +162,6 @@ class EmailViewAppBarWidget extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
|
|
||||||
Widget _getMoveEmailButton(AppLocalizations appLocalizations) => TMailButtonWidget.fromIcon(
|
Widget _getMoveEmailButton(AppLocalizations appLocalizations) => TMailButtonWidget.fromIcon(
|
||||||
key: const Key('email_detailed_move_email_button'),
|
|
||||||
icon: _imagePaths.icMoveEmail,
|
icon: _imagePaths.icMoveEmail,
|
||||||
iconSize: EmailViewAppBarWidgetStyles.buttonIconSize,
|
iconSize: EmailViewAppBarWidgetStyles.buttonIconSize,
|
||||||
iconColor: EmailViewAppBarWidgetStyles.iconColor,
|
iconColor: EmailViewAppBarWidgetStyles.iconColor,
|
||||||
@@ -177,7 +176,6 @@ class EmailViewAppBarWidget extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
|
|
||||||
Widget _getMarkStarButton(AppLocalizations applocalizations) => TMailButtonWidget.fromIcon(
|
Widget _getMarkStarButton(AppLocalizations applocalizations) => TMailButtonWidget.fromIcon(
|
||||||
key: const Key('email_detailed_star_button'),
|
|
||||||
icon: presentationEmail.hasStarred
|
icon: presentationEmail.hasStarred
|
||||||
? _imagePaths.icStar
|
? _imagePaths.icStar
|
||||||
: _imagePaths.icUnStar,
|
: _imagePaths.icUnStar,
|
||||||
@@ -200,7 +198,6 @@ class EmailViewAppBarWidget extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
|
|
||||||
Widget _getDeleteButton(AppLocalizations applocalizations) => TMailButtonWidget.fromIcon(
|
Widget _getDeleteButton(AppLocalizations applocalizations) => TMailButtonWidget.fromIcon(
|
||||||
key: const Key('email_detailed_delete_email_button'),
|
|
||||||
icon: _imagePaths.icDeleteComposer,
|
icon: _imagePaths.icDeleteComposer,
|
||||||
iconSize: EmailViewAppBarWidgetStyles.deleteButtonIconSize,
|
iconSize: EmailViewAppBarWidgetStyles.deleteButtonIconSize,
|
||||||
iconColor: EmailViewAppBarWidgetStyles.iconColor,
|
iconColor: EmailViewAppBarWidgetStyles.iconColor,
|
||||||
|
|||||||
+1
@@ -20,6 +20,7 @@ extension HandleSelectMessageFilterExtension on ThreadController {
|
|||||||
selectedOption,
|
selectedOption,
|
||||||
AppLocalizations.of(context),
|
AppLocalizations.of(context),
|
||||||
imagePaths,
|
imagePaths,
|
||||||
|
key: '${filter.name}_filter',
|
||||||
);
|
);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -12,8 +12,9 @@ class ContextItemFilterMessageOptionAction
|
|||||||
super.action,
|
super.action,
|
||||||
super.selectedAction,
|
super.selectedAction,
|
||||||
this.appLocalizations,
|
this.appLocalizations,
|
||||||
this.imagePaths,
|
this.imagePaths, {
|
||||||
);
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get actionIcon => action.getContextMenuIcon(imagePaths);
|
String get actionIcon => action.getContextMenuIcon(imagePaths);
|
||||||
|
|||||||
@@ -794,12 +794,6 @@
|
|||||||
"placeholders_order": [],
|
"placeholders_order": [],
|
||||||
"placeholders": {}
|
"placeholders": {}
|
||||||
},
|
},
|
||||||
"copy_email_address": "Copy email address",
|
|
||||||
"@copy_email_address": {
|
|
||||||
"type": "text",
|
|
||||||
"placeholders_order": [],
|
|
||||||
"placeholders": {}
|
|
||||||
},
|
|
||||||
"compose_email": "Compose email",
|
"compose_email": "Compose email",
|
||||||
"@compose_email": {
|
"@compose_email": {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
|
|||||||
@@ -805,12 +805,6 @@ class AppLocalizations {
|
|||||||
name: 'hide');
|
name: 'hide');
|
||||||
}
|
}
|
||||||
|
|
||||||
String get copy_email_address {
|
|
||||||
return Intl.message(
|
|
||||||
'Copy email address',
|
|
||||||
name: 'copy_email_address');
|
|
||||||
}
|
|
||||||
|
|
||||||
String get compose_email {
|
String get compose_email {
|
||||||
return Intl.message(
|
return Intl.message(
|
||||||
'Compose email',
|
'Compose email',
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ User-Agent: Twake-Mail/0.13.2 Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15;
|
|||||||
rv:131.0) Gecko/20100101 Firefox/131.0
|
rv:131.0) Gecko/20100101 Firefox/131.0
|
||||||
Content-Type: multipart/alternative;
|
Content-Type: multipart/alternative;
|
||||||
boundary="-=Part.4f.450e1cfbcd355387.192d67ae03d.c367d8042fea24dd=-"
|
boundary="-=Part.4f.450e1cfbcd355387.192d67ae03d.c367d8042fea24dd=-"
|
||||||
List-Post: <mailto:emma-reply-to-list@example.com>
|
|
||||||
|
|
||||||
---=Part.4f.450e1cfbcd355387.192d67ae03d.c367d8042fea24dd=-
|
---=Part.4f.450e1cfbcd355387.192d67ae03d.c367d8042fea24dd=-
|
||||||
Content-Type: text/plain; charset=UTF-8
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# Define users and folders
|
# Define users and folders
|
||||||
users=("alice" "bob" "brian" "charlotte" "david" "emma")
|
users=("alice" "bob" "brian" "charlotte" "david" "emma")
|
||||||
bobFolders=("Search Emails" "Forward Emails" "Disposition" "MailBase64" "Calendar" "Reply Emails" "Reply Emails")
|
bobFolders=("Search Emails" "Forward Emails" "Disposition" "MailBase64" "Calendar" "Reply Emails")
|
||||||
|
|
||||||
# Add users
|
# Add users
|
||||||
for user in "${users[@]}"; do
|
for user in "${users[@]}"; do
|
||||||
|
|||||||
Reference in New Issue
Block a user