Files
status-app/test/e2e/gui/main_window.py

271 lines
11 KiB
Python

import logging
import time
import typing
import allure
import configs
import constants.colors
import driver
from configs.timeouts import APP_LOAD_TIMEOUT_MSEC
from constants import UserAccount, CommunityData
from gui.components.activity_center import ActivityCenter
from gui.components.changes_detected_popup import ChangesDetectedToastMessage
from gui.components.education_popup import EducationPopup
from gui.objects_map.names import continue_StatusButton
from gui.screens.market import MarketScreen
from helpers.chat_helper import skip_message_backup_popup_if_visible, skip_intro_if_visible
from gui.components.context_menu import ContextMenu
from gui.components.splash_screen import SplashScreen
from gui.components.online_identifier import OnlineIdentifier
from gui.elements.button import Button
from gui.elements.object import QObject
from gui.elements.window import Window
from gui.objects_map import names
from gui.screens.community import CommunityScreen
from gui.screens.community_portal import CommunitiesPortal
from gui.screens.messages import MessagesScreen
from gui.screens.onboarding import OnboardingWelcomeToStatusView, ReturningLoginView
from gui.screens.settings import SettingsScreen
from gui.screens.wallet import WalletScreen
from gui.screens.home import HomeScreen
from helpers.onboarding_helper import skip_education_popup_if_visible
from scripts.tools.image import Image
from scripts.utils.decorators import open_with_retries
LOG = logging.getLogger(__name__)
class MainLeftPanel(QObject):
def __init__(self):
super().__init__(names.primaryNavSidebar)
self.profile_button = Button(names.onlineIdentifierButton)
self.home_button = Button(names.homeButton)
self.messages_button = Button(names.chatButton)
self.communities_portal_button = Button(names.communitiesPortalButton)
self.community_template_button = Button(names.statusCommunityMainNavBarListView_CommunityNavBarButton)
self.wallet_button = Button(names.mainWalletButton)
self.activity_center_button = Button(names.activityCenterButton)
self.market_button = Button(names.marketButton)
@allure.step('Click Wallet button and record load time until WalletScreen is visible')
def open_wallet_and_record_load_time(self, timeout_msec: int = configs.timeouts.UI_LOAD_TIMEOUT_MSEC):
start_time = time.time()
self.wallet_button.click()
wallet_screen = WalletScreen()
check_interval = 0.1 # Check every 100ms for better precision
timeout_sec = timeout_msec / 1000
while time.time() - start_time < timeout_sec:
try:
if wallet_screen.left_panel.accounts_list.is_visible:
LOG.info('WalletScreen: is visible')
break
except Exception as e:
LOG.debug("Exception during visibility check: %s", e)
time.sleep(check_interval)
else:
# Timeout reached
load_time = time.time() - start_time
LOG.error(f'WalletScreen is not visible within {timeout_msec} ms (waited {load_time:.3f} seconds)')
raise TimeoutError(f'WalletScreen is not visible within {timeout_msec} ms')
load_time = time.time() - start_time
LOG.info(f'Wallet loaded in {load_time:.3f} seconds')
return wallet_screen, load_time
@allure.step('Click Market button and open Market screen')
@open_with_retries(MarketScreen)
def open_market_screen(self):
return self.market_button
@allure.step('Click Home button and open Home screen')
@open_with_retries(HomeScreen)
def open_home_screen(self):
return self.home_button
@allure.step('Click Chat button and open Messages screen')
@open_with_retries(MessagesScreen)
def open_messages_screen(self):
return self.messages_button
@allure.step('Open Settings screen from the profile context menu')
def open_settings(self) -> SettingsScreen:
self.open_online_identifier().settings_button.click()
return SettingsScreen().wait_until_appears()
@allure.step('Click Activity center button and open Activity center panel')
@open_with_retries(ActivityCenter)
def open_activity_center(self):
return self.activity_center_button
@allure.step('Click Wallet button and open Wallet main screen')
@open_with_retries(WalletScreen)
def open_wallet(self):
return self.wallet_button
@allure.step('Click and open online identifier')
@open_with_retries(OnlineIdentifier)
def open_online_identifier(self):
return self.profile_button
@allure.step('Get communities names')
def communities(self) -> typing.List[str]:
self.community_template_button.real_name['objectName'] = (
names.statusCommunityMainNavBarListView_CommunityNavBarButton['objectName']
)
prefix = 'CommunityNavBarButton_'
return [
str(obj.objectName).removeprefix(prefix)
for obj in driver.findAllObjects(self.community_template_button.real_name)
]
@allure.step('Create community')
def create_community(self, community_data: CommunityData) -> 'CommunityScreen':
communities_portal = self.open_communities_portal()
create_community_form = communities_portal.open_create_community_popup()
assert isinstance(community_data, CommunityData)
app_screen = create_community_form.create_community(community_data)
return app_screen
@property
@allure.step('Get user badge color')
def user_badge_color(self) -> str:
return str(self.profile_button.object.badge.color.name)
@allure.step('Verify: User is online')
def user_is_online(self) -> bool:
return self.user_badge_color == constants.ColorCodes.GREEN.value
@allure.step('Verify: User is offline')
def user_is_offline(self):
return self.user_badge_color == constants.ColorCodes.INACTIVE_GRAY.value
@allure.step('Verify: User is set to automatic')
def user_is_set_to_automatic(self):
return self.user_badge_color == constants.ColorCodes.GREEN.value
@allure.step('Open community portal')
def open_communities_portal(self, attempts: int = 3) -> CommunitiesPortal:
last_exception = None
for attempt in range(1, attempts + 1):
LOG.info('Attempt #%s to open Community portal', attempt)
self.communities_portal_button.click()
skip_intro_if_visible()
skip_message_backup_popup_if_visible()
try:
portal = CommunitiesPortal()
portal.wait_until_appears(
timeout_msec=configs.timeouts.UI_LOAD_TIMEOUT_MSEC,
check_interval=0.1,
)
return portal
except Exception as e:
last_exception = e
LOG.info('Failed to open Communities portal with %s', e)
time.sleep(0.1)
raise Exception(f"Failed to open Communities Portal after {attempts} attempts with {last_exception}")
def _get_community(self, name: str):
self.community_template_button.real_name['objectName'] = f'CommunityNavBarButton_{name}'
try:
return self.community_template_button.object
except Exception as error:
raise LookupError(f'Community: {name} not found in {self.communities()}') from error
@allure.step('Open community')
def open_community(self, name: str) -> CommunityScreen:
self._get_community(name)
self.community_template_button.click()
skip_message_backup_popup_if_visible()
skip_intro_if_visible()
community = CommunityScreen()
community.wait_for_content_loaded()
return community
@allure.step('Click community and record load time until community content is loaded')
def open_community_and_record_load_time(
self, name: str, timeout_msec: int = configs.timeouts.COMMUNITY_LOAD_TIMEOUT_MSEC
):
start_time = time.time()
self._get_community(name)
self.community_template_button.click()
skip_message_backup_popup_if_visible()
skip_intro_if_visible()
community = CommunityScreen()
check_interval = 0.1
timeout_sec = timeout_msec / 1000
while time.time() - start_time < timeout_sec:
try:
if community.is_content_loaded():
LOG.info('CommunityScreen content: is loaded')
break
except Exception as e:
LOG.debug("Exception during content load check: %s", e)
time.sleep(check_interval)
else:
load_time = time.time() - start_time
LOG.error(
'Community content is not loaded within %d ms (waited %.3f seconds)',
timeout_msec,
load_time,
)
raise TimeoutError(f'Community content is not loaded within {timeout_msec} ms')
load_time = time.time() - start_time
LOG.info('Community %s loaded in %.3f seconds', name, load_time)
return community, load_time
@allure.step('Get community logo')
def get_community_logo(self, name: str) -> Image:
self._get_community(name)
return self.community_template_button.image
@allure.step('Open context menu for community')
def open_community_context_menu(self, name: str) -> ContextMenu:
self._get_community(name)
self.community_template_button.right_click()
return ContextMenu().wait_until_appears()
class MainWindow(Window):
def __init__(self):
super().__init__(names.statusDesktop_mainWindow)
self.left_panel = MainLeftPanel()
self.home = HomeScreen()
@allure.step('Create new profile')
def create_profile(self, user_account: UserAccount):
welcome_screen = OnboardingWelcomeToStatusView().wait_until_appears()
profile_view = welcome_screen.open_create_your_profile_view()
create_password_view = profile_view.open_password_view()
create_password_view.create_password(user_account.password)
SplashScreen().wait_until_appears().wait_until_hidden(APP_LOAD_TIMEOUT_MSEC)
skip_education_popup_if_visible()
# since we now struggle with 3 words names, I need to change display name first
left_panel = MainLeftPanel()
settings_screen = left_panel.open_settings()
profile = settings_screen.left_panel.open_profile_settings()
profile.set_name(user_account.name)
ChangesDetectedToastMessage().save_changes()
return self
@allure.step('Log in returning user')
def returning_log_in(self, user_account: UserAccount):
splash_screen = ReturningLoginView().log_in(user_account)
splash_screen.wait_until_appears()
splash_screen.wait_until_hidden(APP_LOAD_TIMEOUT_MSEC)
skip_education_popup_if_visible()
return self
@allure.step('Authorize user')
def authorize_user(self, user_account) -> 'MainWindow':
assert isinstance(user_account, UserAccount)
if ReturningLoginView().is_visible:
return self.returning_log_in(user_account)
else:
return self.create_profile(user_account)