From dbb5568e4a4b17163592ea9afd48ac3c2df997ee Mon Sep 17 00:00:00 2001 From: dab246 Date: Wed, 15 Oct 2025 11:40:34 +0700 Subject: [PATCH] TF-4068 Add E2E test for select identity as default --- .../mailbox/null_quota_exception.dart | 0 .../robots/identity_creator_robot.dart | 25 +++++++ .../robots/mailbox_menu_robot.dart | 2 +- integration_test/robots/profiles_robot.dart | 30 ++++++++ integration_test/robots/setting_robot.dart | 4 + .../create_new_identity_scenario.dart | 75 +++++++++++++++++++ .../set_identity_as_default_scenario.dart | 54 +++++++++++++ .../select_identity_as_default_test.dart | 9 +++ .../identity_creator_form_bottom_view.dart | 1 + .../create_new_identity_button_widget.dart | 1 + .../settings/settings_first_level_view.dart | 1 + 11 files changed, 201 insertions(+), 1 deletion(-) rename integration_test/{integration_test => }/exceptions/mailbox/null_quota_exception.dart (100%) create mode 100644 integration_test/robots/identity_creator_robot.dart create mode 100644 integration_test/robots/profiles_robot.dart create mode 100644 integration_test/scenarios/setting/identity/create_new_identity_scenario.dart create mode 100644 integration_test/scenarios/setting/identity/set_identity_as_default_scenario.dart create mode 100644 integration_test/tests/setting/identity/select_identity_as_default_test.dart diff --git a/integration_test/integration_test/exceptions/mailbox/null_quota_exception.dart b/integration_test/exceptions/mailbox/null_quota_exception.dart similarity index 100% rename from integration_test/integration_test/exceptions/mailbox/null_quota_exception.dart rename to integration_test/exceptions/mailbox/null_quota_exception.dart diff --git a/integration_test/robots/identity_creator_robot.dart b/integration_test/robots/identity_creator_robot.dart new file mode 100644 index 000000000..139bda30b --- /dev/null +++ b/integration_test/robots/identity_creator_robot.dart @@ -0,0 +1,25 @@ +import 'package:core/presentation/views/text/text_field_builder.dart'; +import 'package:flutter/material.dart'; + +import '../base/core_robot.dart'; +import '../extensions/patrol_finder_extension.dart'; + +class IdentityCreatorRobot extends CoreRobot { + IdentityCreatorRobot(super.$); + + Future enterName(String name) async { + final finder = $(TextFieldBuilder).$(TextField); + final isTextFieldFocused = finder + .which((view) => view.focusNode?.hasFocus ?? false) + .exists; + if (!isTextFieldFocused) { + await finder.tap(); + } + await finder.enterTextWithoutTapAction(name); + } + + Future tapSaveIdentityButton() async { + await $.scrollUntilVisible(finder: $(#save_identity_button)); + await $(#save_identity_button).tap(); + } +} diff --git a/integration_test/robots/mailbox_menu_robot.dart b/integration_test/robots/mailbox_menu_robot.dart index 0fb88443f..b75a35ab5 100644 --- a/integration_test/robots/mailbox_menu_robot.dart +++ b/integration_test/robots/mailbox_menu_robot.dart @@ -16,7 +16,7 @@ import 'package:tmail_ui_user/main/routes/route_navigation.dart'; import '../base/core_robot.dart'; import '../exceptions/mailbox/null_inbox_unread_count_exception.dart'; -import '../integration_test/exceptions/mailbox/null_quota_exception.dart'; +import '../exceptions/mailbox/null_quota_exception.dart'; class MailboxMenuRobot extends CoreRobot { MailboxMenuRobot(super.$); diff --git a/integration_test/robots/profiles_robot.dart b/integration_test/robots/profiles_robot.dart new file mode 100644 index 000000000..32adf16d2 --- /dev/null +++ b/integration_test/robots/profiles_robot.dart @@ -0,0 +1,30 @@ +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/identities/widgets/identity_list_tile_builder.dart'; + +import '../base/core_robot.dart'; + +class ProfilesRobot extends CoreRobot { + ProfilesRobot(super.$); + + Future selectIdentityAsDefault( + String identityName, + ImagePaths imagePaths, + ) async { + await $.scrollUntilVisible(finder: $(identityName)); + + await $(IdentityListTileBuilder) + .which( + (widget) { + return widget.identity.name == identityName; + }, + ) + .$(InkWell) + .tap(); + } + + Future tapCreateNewIdentityButton() async { + await $(#create_new_identity_button).tap(); + } +} diff --git a/integration_test/robots/setting_robot.dart b/integration_test/robots/setting_robot.dart index 5226b1443..aa32ac058 100644 --- a/integration_test/robots/setting_robot.dart +++ b/integration_test/robots/setting_robot.dart @@ -15,6 +15,10 @@ class SettingRobot extends CoreRobot { await $(#setting_preferences).tap(); } + Future openProfilesMenuItem() async { + await $(#setting_profiles).tap(); + } + Future switchOnThreadSetting() async { final threadSettingOn = $(ValueKey(AppLocalizations().thread)) .$(#setting_option_switch_on) diff --git a/integration_test/scenarios/setting/identity/create_new_identity_scenario.dart b/integration_test/scenarios/setting/identity/create_new_identity_scenario.dart new file mode 100644 index 000000000..dd16e5d1e --- /dev/null +++ b/integration_test/scenarios/setting/identity/create_new_identity_scenario.dart @@ -0,0 +1,75 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:tmail_ui_user/features/identity_creator/presentation/identity_creator_view.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +import '../../../base/base_test_scenario.dart'; +import '../../../robots/identity_creator_robot.dart'; +import '../../../robots/mailbox_menu_robot.dart'; +import '../../../robots/profiles_robot.dart'; +import '../../../robots/setting_robot.dart'; +import '../../../robots/thread_robot.dart'; + +class CreateNewIdentityScenario extends BaseTestScenario { + final List? identityNames; + + const CreateNewIdentityScenario(super.$, {this.identityNames}); + + @override + Future runTestLogic() async { + final threadRobot = ThreadRobot($); + final mailboxMenuRobot = MailboxMenuRobot($); + final settingRobot = SettingRobot($); + final profilesRobot = ProfilesRobot($); + final identityCreatorRobot = IdentityCreatorRobot($); + final appLocalizations = AppLocalizations(); + + await threadRobot.openMailbox(); + await _expectUserAvatarVisible(); + + await mailboxMenuRobot.openSetting(); + await _expectSettingViewVisible(appLocalizations); + await $.pumpAndTrySettle(); + await _expectProfilesMenuItemVisible(); + + await settingRobot.openProfilesMenuItem(); + await $.pumpAndTrySettle(); + await _expectCreateNewIdentityButtonVisible(); + + if (identityNames?.isNotEmpty == true) { + for (var name in identityNames!) { + await profilesRobot.tapCreateNewIdentityButton(); + await _expectIdentityCreatorViewVisible(); + await identityCreatorRobot.enterName(name); + await identityCreatorRobot.tapSaveIdentityButton(); + await $.pumpAndTrySettle(duration: const Duration(seconds: 1)); + await _expectIdentityVisible(name); + } + } else { + await profilesRobot.tapCreateNewIdentityButton(); + await _expectIdentityCreatorViewVisible(); + await identityCreatorRobot.enterName('New Identity'); + await identityCreatorRobot.tapSaveIdentityButton(); + await $.pumpAndTrySettle(duration: const Duration(seconds: 1)); + await _expectIdentityVisible('New Identity'); + } + } + + Future _expectUserAvatarVisible() => expectViewVisible($(#user_avatar)); + + Future _expectSettingViewVisible(AppLocalizations appLocalizations) => + expectViewVisible($(find.text(appLocalizations.settings))); + + Future _expectProfilesMenuItemVisible() async { + await expectViewVisible($(#setting_profiles)); + } + + Future _expectCreateNewIdentityButtonVisible() => + expectViewVisible($(#create_new_identity_button)); + + Future _expectIdentityCreatorViewVisible() => + expectViewVisible($(IdentityCreatorView)); + + Future _expectIdentityVisible(String name) async { + await expectViewVisible($(name)); + } +} diff --git a/integration_test/scenarios/setting/identity/set_identity_as_default_scenario.dart b/integration_test/scenarios/setting/identity/set_identity_as_default_scenario.dart new file mode 100644 index 000000000..758ec6ad7 --- /dev/null +++ b/integration_test/scenarios/setting/identity/set_identity_as_default_scenario.dart @@ -0,0 +1,54 @@ +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:tmail_ui_user/features/manage_account/presentation/identities/widgets/identity_list_tile_builder.dart'; + +import '../../../base/base_test_scenario.dart'; +import '../../../robots/profiles_robot.dart'; +import 'create_new_identity_scenario.dart'; + +class SetIdentityAsDefaultScenario extends BaseTestScenario { + const SetIdentityAsDefaultScenario(super.$); + + @override + Future runTestLogic() async { + final profilesRobot = ProfilesRobot($); + final imagePaths = ImagePaths(); + final createNewIdentityScenario = CreateNewIdentityScenario( + $, + identityNames: ['Default Identity 1', 'Default Identity 2'], + ); + await createNewIdentityScenario.runTestLogic(); + await $.pumpAndTrySettle(); + + await profilesRobot.selectIdentityAsDefault( + 'Default Identity 1', + imagePaths, + ); + await $.pumpAndTrySettle(); + _expectIdentityAsDefaultVisible('Default Identity 1', imagePaths); + + await profilesRobot.selectIdentityAsDefault( + 'Default Identity 2', + imagePaths, + ); + await $.pumpAndTrySettle(); + _expectIdentityAsDefaultVisible('Default Identity 2', imagePaths); + } + + void _expectIdentityAsDefaultVisible(String name, ImagePaths imagePaths) { + expect( + $(IdentityListTileBuilder) + .which( + (widget) { + return widget.identity.name == name; + }, + ) + .$(TMailButtonWidget) + .which( + (widget) => widget.icon == imagePaths.icRadioSelected) + .exists, + true, + ); + } +} diff --git a/integration_test/tests/setting/identity/select_identity_as_default_test.dart b/integration_test/tests/setting/identity/select_identity_as_default_test.dart new file mode 100644 index 000000000..38d047adc --- /dev/null +++ b/integration_test/tests/setting/identity/select_identity_as_default_test.dart @@ -0,0 +1,9 @@ +import '../../../base/test_base.dart'; +import '../../../scenarios/setting/identity/set_identity_as_default_scenario.dart'; + +void main() { + TestBase().runPatrolTest( + description: 'Should see identity as default when select identity as default', + scenarioBuilder: ($) => SetIdentityAsDefaultScenario($), + ); +} \ No newline at end of file diff --git a/lib/features/identity_creator/presentation/widgets/identity_creator_form_bottom_view.dart b/lib/features/identity_creator/presentation/widgets/identity_creator_form_bottom_view.dart index 6583b9f1e..d9a5a71f9 100644 --- a/lib/features/identity_creator/presentation/widgets/identity_creator_form_bottom_view.dart +++ b/lib/features/identity_creator/presentation/widgets/identity_creator_form_bottom_view.dart @@ -72,6 +72,7 @@ class IdentityCreatorFormBottomView extends StatelessWidget { ); } else { return ConfirmDialogButton( + key: const Key('save_identity_button'), label: actionType.getPositiveButtonTitle(appLocalizations), backgroundColor: AppColor.primaryMain, textColor: Colors.white, diff --git a/lib/features/manage_account/presentation/identities/widgets/create_new_identity_button_widget.dart b/lib/features/manage_account/presentation/identities/widgets/create_new_identity_button_widget.dart index f7c6e10d8..95014160d 100644 --- a/lib/features/manage_account/presentation/identities/widgets/create_new_identity_button_widget.dart +++ b/lib/features/manage_account/presentation/identities/widgets/create_new_identity_button_widget.dart @@ -22,6 +22,7 @@ class CreateNewIdentityButtonWidget extends StatelessWidget { @override Widget build(BuildContext context) { return TMailButtonWidget( + key: const Key('create_new_identity_button'), text: AppLocalizations.of(context).createNewIdentity, icon: imagePaths.icAddIdentity, backgroundColor: AppColor.primaryMain, diff --git a/lib/features/manage_account/presentation/menu/settings/settings_first_level_view.dart b/lib/features/manage_account/presentation/menu/settings/settings_first_level_view.dart index f28aa9f36..4953fe5c7 100644 --- a/lib/features/manage_account/presentation/menu/settings/settings_first_level_view.dart +++ b/lib/features/manage_account/presentation/menu/settings/settings_first_level_view.dart @@ -50,6 +50,7 @@ class SettingsFirstLevelView extends GetWidget { endIndent: SettingsUtils.getHorizontalPadding(context, controller.responsiveUtils) ), SettingFirstLevelTileBuilder( + key: const Key('setting_profiles'), AppLocalizations.of(context).profiles, AccountMenuItem.profiles.getIcon(controller.imagePaths), subtitle: AppLocalizations.of(context).profilesSettingExplanation,