Skip to content

Commit dd07136

Browse files
committed
test(e2e_appium): utils
1 parent 991d19d commit dd07136

14 files changed

+1411
-1
lines changed

test/e2e_appium/conftest.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
from .config.logging_config import get_logger
88
from .core import EnvironmentSwitcher
99
from .utils.lambdatest_reporter import LambdaTestReporter
10+
from .utils.screenshot import save_screenshot, save_page_source
1011

1112

1213
# Expose fixture modules without star imports
1314
pytest_plugins = [
14-
"fixtures.onboarding_fixture",
15+
# "fixtures.onboarding_fixture", # Disabled - using BaseAppReadyTest instead
1516
]
1617

1718

@@ -161,6 +162,51 @@ def pytest_runtest_makereport(item, call):
161162
logger = get_logger("session")
162163
logger.error(f"Failed to report test result to LambdaTest: {e}")
163164

165+
# Get screenshot and page source artifacts
166+
try:
167+
if getattr(rep, "failed", False) and not getattr(item, "_failure_artifacts_saved", False):
168+
driver = None
169+
try:
170+
if hasattr(item, "instance") and hasattr(item.instance, "driver"):
171+
driver = item.instance.driver
172+
except Exception:
173+
driver = None
174+
175+
if driver:
176+
# Resolve screenshots directory from environment config; fallback to 'screenshots'
177+
try:
178+
env_name = os.getenv("CURRENT_TEST_ENVIRONMENT", "lambdatest")
179+
switcher = EnvironmentSwitcher()
180+
env_config = switcher.switch_to(env_name)
181+
screenshots_dir = env_config.directories.get("screenshots", "screenshots")
182+
except Exception:
183+
screenshots_dir = "screenshots"
184+
185+
test_id = getattr(item, "name", "test") + (f"__{rep.when}" if getattr(rep, "when", None) else "")
186+
187+
s_path = None
188+
x_path = None
189+
try:
190+
s_path = save_screenshot(driver, str(screenshots_dir), f"FAILED_{test_id}")
191+
except Exception:
192+
pass
193+
try:
194+
x_path = save_page_source(driver, str(screenshots_dir), f"FAILED_{test_id}")
195+
except Exception:
196+
pass
197+
198+
log = get_logger("conftest")
199+
if s_path:
200+
log.info(f"Saved failure screenshot: {s_path}")
201+
if x_path:
202+
log.info(f"Saved failure page source: {x_path}")
203+
204+
setattr(item, "_failure_artifacts_saved", True)
205+
except Exception as e:
206+
log = get_logger("conftest")
207+
log.warning(f"Artifact capture failed: {e}")
208+
209+
164210
def pytest_terminal_summary(terminalreporter, exitstatus, config):
165211
if not _logging_setup:
166212
return
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from .user_profile_service import UserProfileService
2+
from .app_state_manager import AppStateManager
3+
from .app_initialization_manager import AppInitializationManager
4+
5+
__all__ = [
6+
"UserProfileService",
7+
"AppStateManager",
8+
"AppInitializationManager",
9+
]
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import time
2+
3+
from config.logging_config import get_logger
4+
from utils.gestures import Gestures
5+
6+
7+
class AppInitializationManager:
8+
9+
def __init__(self, driver):
10+
self.driver = driver
11+
self.gestures = Gestures(driver)
12+
self.logger = get_logger("app_initialization")
13+
14+
def perform_initial_activation(
15+
self, timeout: float = 15.0, interval: float = 2.0
16+
) -> bool:
17+
"""Perform initial app activation until UI appears or timeout is reached."""
18+
self.logger.debug("🚀 Starting app initialization sequence")
19+
20+
self._wait_for_session_ready()
21+
22+
deadline = time.time() + timeout
23+
24+
while time.time() < deadline:
25+
if not self._should_perform_activation_tap():
26+
self.logger.debug("↷ UI already present - skipping activation")
27+
return True
28+
29+
if self._perform_activation_tap():
30+
if self._wait_for_ui_response(timeout=interval):
31+
self.logger.info("✓ App UI surfaced after activation")
32+
return True
33+
34+
self.logger.warning("⚠ App activation timeout - UI may not be ready")
35+
return False
36+
37+
def _wait_for_session_ready(
38+
self, timeout: float = 2.0, poll_interval: float = 0.2
39+
) -> None:
40+
deadline = time.time() + timeout
41+
while time.time() < deadline:
42+
try:
43+
_ = self.driver.get_window_size()
44+
try:
45+
_ = self.driver.page_source
46+
except Exception:
47+
pass
48+
break
49+
except Exception:
50+
time.sleep(poll_interval)
51+
52+
def _should_perform_activation_tap(self) -> bool:
53+
ui_checks = [
54+
self._is_home_container_visible,
55+
self._is_welcome_back_visible,
56+
self._is_welcome_visible,
57+
self._is_ui_content_present,
58+
]
59+
60+
for check in ui_checks:
61+
try:
62+
if check():
63+
return False
64+
except Exception:
65+
continue
66+
67+
return True
68+
69+
def _is_home_container_visible(self) -> bool:
70+
try:
71+
from pages.onboarding import HomePage
72+
73+
main_app = HomePage(self.driver)
74+
return main_app.is_element_visible(
75+
main_app.locators.HOME_CONTAINER, timeout=1
76+
)
77+
except Exception:
78+
return False
79+
80+
def _is_welcome_back_visible(self) -> bool:
81+
try:
82+
from pages.onboarding import WelcomeBackPage
83+
84+
welcome_back = WelcomeBackPage(self.driver)
85+
return welcome_back.is_welcome_back_screen_displayed(timeout=1)
86+
except Exception:
87+
return False
88+
89+
def _is_welcome_visible(self) -> bool:
90+
try:
91+
from pages.onboarding import WelcomePage
92+
93+
welcome = WelcomePage(self.driver)
94+
return welcome.is_screen_displayed(timeout=1)
95+
except Exception:
96+
return False
97+
98+
def _is_ui_content_present(self) -> bool:
99+
try:
100+
src = self.driver.page_source
101+
ui_markers = [
102+
"startupOnboardingLayout",
103+
"homeContainer.homeDock",
104+
"Welcome to Status",
105+
]
106+
return any(marker in src for marker in ui_markers)
107+
except Exception:
108+
return False
109+
110+
def _perform_activation_tap(self) -> bool:
111+
try:
112+
coords = self._get_safe_tap_coordinates()
113+
if self.gestures.double_tap(coords[0], coords[1]):
114+
self.logger.debug("✓ Activation double-tap performed")
115+
return True
116+
elif self.gestures.tap(coords[0], coords[1]):
117+
self.logger.debug("✓ Activation tap performed")
118+
return True
119+
else:
120+
self.logger.debug("⚠ Activation tap failed")
121+
return False
122+
except Exception as e:
123+
self.logger.debug(f"⚠ Activation tap error: {e}")
124+
return False
125+
126+
def _get_safe_tap_coordinates(self) -> tuple:
127+
try:
128+
size = self.driver.get_window_size()
129+
return (size["width"] // 2, size["height"] // 2)
130+
except Exception:
131+
self.logger.warning("⚠ Could not get window size; using fallback coords")
132+
return (500, 300)
133+
134+
def _wait_for_ui_response(
135+
self, timeout: int = 5, poll_interval: float = 0.5
136+
) -> bool:
137+
deadline = time.time() + timeout
138+
139+
while time.time() < deadline:
140+
if not self._should_perform_activation_tap():
141+
return True
142+
time.sleep(poll_interval)
143+
144+
return False
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import time
2+
3+
from config.logging_config import get_logger
4+
from core.models import TestAppState
5+
6+
7+
class AppStateManager:
8+
9+
def __init__(self, driver):
10+
self.driver = driver
11+
self.logger = get_logger("app_state_manager")
12+
self.state = TestAppState()
13+
14+
def detect_current_state(self) -> TestAppState:
15+
self.logger.debug("🔍 Detecting app state...")
16+
17+
if self._is_welcome_screen_displayed():
18+
self._set_welcome_state()
19+
elif self._is_welcome_back_displayed():
20+
self._set_welcome_back_state()
21+
elif self._is_app_section_loaded():
22+
self._set_app_section_state()
23+
elif self._is_home_loaded():
24+
self._set_home_state()
25+
else:
26+
self._set_unknown_state()
27+
28+
return self.state
29+
30+
def wait_for_app_ready(self, timeout: int = 30, poll_interval: float = 0.5) -> bool:
31+
deadline = time.time() + timeout
32+
while time.time() < deadline:
33+
try:
34+
self.detect_current_state()
35+
if self.state.is_home_loaded or self.state.requires_authentication:
36+
return True
37+
except Exception:
38+
pass
39+
time.sleep(poll_interval)
40+
return False
41+
42+
def _is_welcome_screen_displayed(self) -> bool:
43+
try:
44+
from pages.onboarding import WelcomePage
45+
46+
welcome = WelcomePage(self.driver)
47+
return welcome.is_screen_displayed(timeout=3)
48+
except Exception:
49+
return False
50+
51+
def _is_welcome_back_displayed(self) -> bool:
52+
try:
53+
from pages.onboarding import WelcomeBackPage
54+
55+
welcome_back = WelcomeBackPage(self.driver)
56+
return welcome_back.is_welcome_back_screen_displayed(timeout=5)
57+
except Exception:
58+
return False
59+
60+
def _is_app_section_loaded(self) -> bool:
61+
try:
62+
from pages.app import App
63+
64+
app = App(self.driver)
65+
section = app.active_section()
66+
return section in (
67+
"home",
68+
"messaging",
69+
"wallet",
70+
"communities",
71+
"market",
72+
"settings",
73+
)
74+
except Exception:
75+
return False
76+
77+
def _is_home_loaded(self) -> bool:
78+
try:
79+
from pages.onboarding import HomePage
80+
81+
main_app = HomePage(self.driver)
82+
return main_app.is_home_loaded()
83+
except Exception:
84+
return False
85+
86+
def _set_welcome_state(self):
87+
self.state.is_home_loaded = False
88+
self.state.current_screen = "welcome"
89+
self.state.requires_authentication = False
90+
self.state.has_existing_profiles = False
91+
self.logger.debug("✓ Welcome screen detected")
92+
93+
def _set_welcome_back_state(self):
94+
self.state.has_existing_profiles = True
95+
self.state.current_screen = "welcome_back"
96+
self.state.requires_authentication = True
97+
self.logger.debug("✓ Welcome back screen detected")
98+
99+
def _set_app_section_state(self):
100+
try:
101+
from pages.app import App
102+
103+
app = App(self.driver)
104+
section = app.active_section()
105+
if section == "home":
106+
self.state.is_home_loaded = True
107+
self.state.current_screen = "home"
108+
self.state.requires_authentication = False
109+
self.logger.debug("✓ Home detected (container)")
110+
else:
111+
self.state.is_home_loaded = False
112+
self.state.current_screen = section
113+
self.state.requires_authentication = False
114+
self.logger.debug(f"✓ Section detected: {section}")
115+
except Exception:
116+
self._set_unknown_state()
117+
118+
def _set_home_state(self):
119+
self.state.is_home_loaded = True
120+
self.state.current_screen = "home"
121+
self.state.requires_authentication = False
122+
self.logger.debug("✓ Home detected (fallback)")
123+
124+
def _set_unknown_state(self):
125+
self.state.current_screen = "unknown"
126+
self.logger.debug("? Unknown app state detected")

0 commit comments

Comments
 (0)