Skip to content

Commit ab01a8d

Browse files
authored
e2e appium/test settings password change password (#18977)
* test(e2e_appium): test_settings_password_change_password password change test ported from desktop e2e
1 parent 51540fe commit ab01a8d

17 files changed

+481
-69
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
"""Shared constants for the e2e Appium test suite."""
2+
3+
from .app_sections import AppSections
4+
5+
__all__ = ["AppSections"]
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
"""Shared constants for the e2e Appium test suite."""
2+
3+
4+
class AppSections:
5+
"""Identifiers for the high-level application sections."""
6+
7+
HOME = "home"
8+
WALLET = "wallet"
9+
MARKET = "market"
10+
MESSAGING = "messaging"
11+
COMMUNITIES = "communities"
12+
SETTINGS = "settings"

test/e2e_appium/core/test_context.py

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -175,14 +175,11 @@ def settings(self):
175175

176176
@property
177177
def welcome_back(self):
178-
class SimpleWelcomeBack:
179-
def is_welcome_back_screen_displayed(self, timeout=10):
180-
return False
181-
182-
def perform_login(self, password):
183-
return False
178+
if not self._welcome_back:
179+
from pages.onboarding import WelcomeBackPage
184180

185-
return SimpleWelcomeBack()
181+
self._welcome_back = WelcomeBackPage(self.driver)
182+
return self._welcome_back
186183

187184
@property
188185
def user_service(self) -> UserProfileService:
@@ -267,8 +264,15 @@ def restart_app_and_login(self) -> bool:
267264
self.logger.error("App restart failed")
268265
return False
269266

270-
# Wait for app to stabilize and present either home or auth
271-
self.wait_for_app_post_restart()
267+
try:
268+
manager = self._app_initialization or AppInitializationManager(self.driver)
269+
if not self._app_initialization:
270+
self._app_initialization = manager
271+
manager.perform_initial_activation(timeout=3)
272+
except Exception as activation_err:
273+
self.logger.debug(
274+
"Post-restart activation attempt failed: %s", activation_err
275+
)
272276

273277
# Detect new state and handle authentication
274278
self.app_state_manager.detect_current_state()
@@ -289,14 +293,18 @@ def get_home(self, ensure: bool = True, auto_create: bool = True) -> HomePage:
289293

290294
if not self.app_state.is_home_loaded:
291295
# Try existing-user login if authentication is required
292-
if self.app_state.requires_authentication:
296+
if self.app_state.requires_authentication and self.user_service.current_user:
293297
try:
294298
self.logger.info(
295299
"Auth required - attempting existing user login"
296300
)
297301
self.login_existing_user()
298302
except Exception as e:
299303
self.logger.warning(f"Existing user login failed: {e}")
304+
elif self.app_state.requires_authentication:
305+
self.logger.info(
306+
"Auth required but no known test user; skipping auto-login"
307+
)
300308

301309
# If still not loaded and allowed, create a user
302310
if not self.app_state.is_home_loaded and auto_create:
@@ -347,6 +355,7 @@ def cleanup(self):
347355
self._user_service = None
348356
self._app_state_manager = None
349357
self._app_initialization = None
358+
self._welcome_back = None
350359

351360
self.logger.info("✅ TestContext cleanup completed")
352361

@@ -418,26 +427,6 @@ def _handle_post_restart_authentication(self) -> bool:
418427

419428
return False
420429

421-
def wait_for_app_post_restart(
422-
self, timeout: Optional[int] = None, poll_interval: float = 0.5
423-
) -> bool:
424-
"""Public helper to wait for app readiness after a restart using YAML defaults."""
425-
effective_timeout = timeout
426-
try:
427-
if (
428-
effective_timeout is None
429-
and self._session_manager
430-
and self._session_manager.env_config
431-
):
432-
effective_timeout = self._session_manager.env_config.timeouts.get(
433-
"default", 30
434-
)
435-
except Exception:
436-
effective_timeout = effective_timeout or 30
437-
return self._wait_for_app_ready(
438-
timeout=int(effective_timeout or 30), poll_interval=poll_interval
439-
)
440-
441430
def _wait_for_app_ready(
442431
self, timeout: int = 30, poll_interval: float = 0.5
443432
) -> bool:

test/e2e_appium/locators/onboarding/wallet/wallet_locators.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
class WalletLocators(BaseLocators):
44

5-
WALLET_HEADER = BaseLocators.accessibility_id("Wallet")
5+
WALLET_HEADER = BaseLocators.content_desc_contains("walletHeader")
66
WALLET_FOOTER_SEND_BUTTON = BaseLocators.xpath(
7-
"//android.view.View.VirtualChild[@content-desc='Send [tid:walletFooterSendButton]']"
7+
"//*[contains(@resource-id, 'walletFooterSendButton')]"
88
)
99
ASSETS_TAB = BaseLocators.text_contains("Assets")
1010
ACTIVITY_TAB = BaseLocators.text_contains("Activity")

test/e2e_appium/locators/onboarding/welcome_back_screen_locators.py

Lines changed: 5 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44

55

66
class WelcomeBackScreenLocators(BaseLocators):
7-
"""Locators for the Welcome Back screen (returning users)."""
7+
"""Locators for the Welcome Back (returning user) screen."""
88

9-
# TODO: Replace fallbacks with accessibility_id/tid
10-
119
# Screen identification
1210
LOGIN_SCREEN = BaseLocators.xpath(
1311
"//*[contains(@resource-id, 'LoginScreen_QMLTYPE')]"
@@ -16,36 +14,10 @@ class WelcomeBackScreenLocators(BaseLocators):
1614
"QGuiApplication.mainWindow.startupOnboardingLayout"
1715
)
1816

19-
# User selection elements
20-
USER_SELECTOR = BaseLocators.xpath(
21-
"//*[contains(@resource-id, 'loginUserSelector')]"
22-
)
23-
USER_SELECTOR_DELEGATE = BaseLocators.xpath(
24-
"//*[contains(@resource-id, 'LoginUserSelectorDelegate_QMLTYPE')]"
25-
)
26-
27-
# Password input elements
28-
PASSWORD_BOX = BaseLocators.xpath("//*[contains(@resource-id, 'passwordBox')]")
2917
PASSWORD_INPUT = BaseLocators.xpath(
3018
"//*[contains(@resource-id, 'loginPasswordInput')]"
3119
)
32-
PASSWORD_INPUT_BY_DESC = BaseLocators.content_desc_exact("Password")
33-
34-
# Login action
35-
LOGIN_BUTTON = BaseLocators.xpath("//*[contains(@resource-id, 'loginButton')]")
36-
LOGIN_BUTTON_BY_DESC = BaseLocators.content_desc_exact("Log In")
37-
38-
# Fallback locators for robustness
39-
LOGIN_BUTTON_FALLBACKS = [
40-
BaseLocators.xpath("//*[contains(@resource-id, 'loginButton')]"),
41-
BaseLocators.content_desc_exact("Log In"),
42-
BaseLocators.text_exact("Log In"),
43-
]
44-
45-
PASSWORD_INPUT_FALLBACKS = [
46-
BaseLocators.xpath("//*[contains(@resource-id, 'loginPasswordInput')]"),
47-
BaseLocators.content_desc_exact("Password"),
48-
BaseLocators.xpath(
49-
"//android.widget.EditText[contains(@content-desc, 'Password')]"
50-
),
51-
]
20+
PASSWORD_INPUT_OVERLAY = BaseLocators.xpath(
21+
"//*[contains(@resource-id, 'loginPasswordInput')]"
22+
)
23+
LOGIN_BUTTON = BaseLocators.content_desc_contains("[tid:loginButton]")
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from ..base_locators import BaseLocators
2+
3+
4+
class PasswordChangeLocators(BaseLocators):
5+
CURRENT_PASSWORD_CONTAINER = BaseLocators.content_desc_exact(
6+
"Enter current password"
7+
)
8+
CURRENT_PASSWORD_INPUT = BaseLocators.xpath(
9+
"//*[contains(@resource-id, 'passwordViewCurrentPassword')]"
10+
)
11+
NEW_PASSWORD_INPUT = BaseLocators.xpath(
12+
"//*[contains(@resource-id, 'passwordViewNewPassword') and not(contains(@resource-id, 'Confirm'))]"
13+
)
14+
CONFIRM_PASSWORD_INPUT = BaseLocators.xpath(
15+
"//*[contains(@resource-id, 'passwordViewNewPasswordConfirm')]"
16+
)
17+
CHANGE_PASSWORD_BUTTON = BaseLocators.xpath(
18+
"//*[contains(@resource-id, 'changePasswordModalSubmitButton') or "
19+
"contains(@content-desc, 'changePasswordModalSubmitButton')]"
20+
)
21+
22+
23+
class ChangePasswordModalLocators(BaseLocators):
24+
MODAL_CONTAINER = BaseLocators.xpath(
25+
"//*[@resource-id='QGuiApplication.mainWindow.ConfirmChangePasswordModal']"
26+
)
27+
PRIMARY_BUTTON = BaseLocators.xpath(
28+
"//*[@resource-id='QGuiApplication.mainWindow.ConfirmChangePasswordModal']"
29+
"//*[contains(@content-desc, 'tid:changePasswordModalSubmitButton')]"
30+
)
31+
STATUS_MESSAGE = BaseLocators.xpath(
32+
"//*[@resource-id='QGuiApplication.mainWindow.ConfirmChangePasswordModal']"
33+
"//*[contains(@resource-id, 'statusListItemSubTitle')]"
34+
)

test/e2e_appium/locators/settings/settings_locators.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ class SettingsLocators(BaseLocators):
1313
BACKUP_RECOVERY_MENU_ITEM = BaseLocators.content_desc_contains("[tid:19-MenuItem]")
1414

1515
PROFILE_MENU_ITEM = BaseLocators.xpath("//*[contains(@resource-id,'0-MenuItem')]")
16+
PASSWORD_MENU_ITEM = BaseLocators.content_desc_contains("[tid:1-MenuItem]")
17+
PASSWORD_MENU_ITEM_TEXT = BaseLocators.text_contains("Password")
1618

1719
SIGN_OUT_AND_QUIT = BaseLocators.text_contains("Sign out & Quit")
1820
SIGN_OUT_AND_QUIT_ALT = BaseLocators.xpath(

test/e2e_appium/pages/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
CreateProfilePage,
1010
PasswordPage,
1111
SplashScreen,
12+
WelcomeBackPage,
1213
)
1314

1415
__all__ = [
@@ -20,4 +21,5 @@
2021
"CreateProfilePage",
2122
"PasswordPage",
2223
"SplashScreen",
24+
"WelcomeBackPage",
2325
]

test/e2e_appium/pages/base_page.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ def safe_click(
165165
)
166166
self.logger.error(message)
167167
self.take_screenshot(f"click_failure_{locators_to_try[0][1]}")
168+
self.dump_page_source(f"click_failure_{locators_to_try[0][1]}")
168169
raise ElementInteractionError(message, str(locators_to_try[0]), "click")
169170

170171
def safe_input(self, locator, text: str, timeout: Optional[int] = None) -> bool:

test/e2e_appium/pages/onboarding/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from .loading_page import SplashScreen
88
from .home_page import HomePage
99
from .seed_phrase_input_page import SeedPhraseInputPage
10+
from .welcome_back_page import WelcomeBackPage
1011
from .main_app_page import MainAppPage
1112

1213
__all__ = [
@@ -17,5 +18,6 @@
1718
"SplashScreen",
1819
"HomePage",
1920
"SeedPhraseInputPage",
21+
"WelcomeBackPage",
2022
"MainAppPage",
2123
]

0 commit comments

Comments
 (0)