mirror of
https://github.com/status-im/status-desktop.git
synced 2025-01-12 15:24:39 +00:00
fix(wallet) fix Add Account Modal and wallet tests
- fix add-account-modal custom derivation checkbox blocking all workflows - fix, improve and enable wallet tests - wait_for_text_matching alternative, to is_text_matching, to check also for content as squish driver API - add objectName based lookup for in some places where user-text was used - add workaround to retry for 10 seconds add watch due to flakiness - rename SquishDriver.type to type.text not to conflict with python's type - add optional timeout to some APIs - ignore error for extra step in reaching onboarding seedphrase in linux Updates: #9576
This commit is contained in:
parent
1c7c0d7d81
commit
16ed8739e8
@ -168,7 +168,6 @@ QtObject:
|
||||
let cacheKey = getTokenPriceCacheKey(cryptoKey, fiatKey)
|
||||
if self.priceCache.isCached(cacheKey):
|
||||
return self.priceCache.get(cacheKey) * factor
|
||||
var prices = initTable[string, Table[string, float]]()
|
||||
|
||||
try:
|
||||
let response = backend.fetchPrices(@[cryptoKey], @[fiatKey])
|
||||
@ -180,7 +179,7 @@ QtObject:
|
||||
let errDesription = e.msg
|
||||
error "error: ", errDesription
|
||||
return 0.0
|
||||
|
||||
|
||||
proc getCachedTokenPrice*(self: Service, crypto: string, fiat: string, fetchIfNotPresent: bool = false): float64 =
|
||||
let (cryptoKey, factor) = getCryptoKeyAndFactor(crypto)
|
||||
|
||||
|
@ -5,13 +5,13 @@ import drivers.SDKeyboardCommands as keyCommands
|
||||
|
||||
def start_application(app_name: str):
|
||||
driver.start_application(app_name)
|
||||
|
||||
|
||||
def click_on_an_object(objName: str):
|
||||
driver.click_obj_by_name(objName)
|
||||
|
||||
driver.click_obj_by_name(objName)
|
||||
|
||||
def input_text(text: str, objName: str):
|
||||
driver.type(objName, text)
|
||||
|
||||
driver.type_text(objName, text)
|
||||
|
||||
def object_not_enabled(objName: str):
|
||||
verification.verify_object_enabled(objName, 500, False)
|
||||
|
||||
|
@ -4,32 +4,32 @@ from drivers.SquishDriverVerification import *
|
||||
|
||||
|
||||
def input_seed_phrase(input_object_name: str, words: str):
|
||||
type(input_object_name + "1", words[0])
|
||||
type(input_object_name + "2", words[1])
|
||||
type(input_object_name + "3", words[2])
|
||||
type(input_object_name + "4", words[3])
|
||||
type(input_object_name + "5", words[4])
|
||||
type(input_object_name + "6", words[5])
|
||||
type(input_object_name + "7", words[6])
|
||||
type(input_object_name + "8", words[7])
|
||||
type(input_object_name + "9", words[8])
|
||||
type(input_object_name + "10", words[9])
|
||||
type(input_object_name + "11", words[10])
|
||||
type(input_object_name + "12", words[11])
|
||||
type_text(input_object_name + "1", words[0])
|
||||
type_text(input_object_name + "2", words[1])
|
||||
type_text(input_object_name + "3", words[2])
|
||||
type_text(input_object_name + "4", words[3])
|
||||
type_text(input_object_name + "5", words[4])
|
||||
type_text(input_object_name + "6", words[5])
|
||||
type_text(input_object_name + "7", words[6])
|
||||
type_text(input_object_name + "8", words[7])
|
||||
type_text(input_object_name + "9", words[8])
|
||||
type_text(input_object_name + "10", words[9])
|
||||
type_text(input_object_name + "11", words[10])
|
||||
type_text(input_object_name + "12", words[11])
|
||||
|
||||
if len(words) >= 18:
|
||||
type(input_object_name + "13", words[12])
|
||||
type(input_object_name + "14", words[13])
|
||||
type(input_object_name + "15", words[14])
|
||||
type(input_object_name + "16", words[15])
|
||||
type(input_object_name + "17", words[16])
|
||||
type(input_object_name + "18", words[17])
|
||||
type_text(input_object_name + "13", words[12])
|
||||
type_text(input_object_name + "14", words[13])
|
||||
type_text(input_object_name + "15", words[14])
|
||||
type_text(input_object_name + "16", words[15])
|
||||
type_text(input_object_name + "17", words[16])
|
||||
type_text(input_object_name + "18", words[17])
|
||||
|
||||
if len(words) == 24:
|
||||
type(input_object_name + "19", words[18])
|
||||
type(input_object_name + "20", words[19])
|
||||
type(input_object_name + "21", words[20])
|
||||
type(input_object_name + "22", words[21])
|
||||
type(input_object_name + "23", words[22])
|
||||
type(input_object_name + "24", words[23])
|
||||
type_text(input_object_name + "19", words[18])
|
||||
type_text(input_object_name + "20", words[19])
|
||||
type_text(input_object_name + "21", words[20])
|
||||
type_text(input_object_name + "22", words[21])
|
||||
type_text(input_object_name + "23", words[22])
|
||||
type_text(input_object_name + "24", words[23])
|
||||
|
||||
|
@ -2,13 +2,13 @@ from drivers.SquishDriver import *
|
||||
|
||||
|
||||
def press_enter(objName: str):
|
||||
type(objName, "<Return>")
|
||||
type_text(objName, "<Return>")
|
||||
|
||||
def press_backspace(objName: str):
|
||||
type(objName, "<Backspace>")
|
||||
type_text(objName, "<Backspace>")
|
||||
|
||||
def press_escape(objName: str):
|
||||
type(objName, "<Escape>")
|
||||
type_text(objName, "<Escape>")
|
||||
|
||||
def press_select_all(objName: str):
|
||||
click_obj_by_name(objName)
|
||||
|
@ -120,8 +120,12 @@ def hover_and_click_object_by_name(objName: str):
|
||||
squish.mouseClick(obj, squish.Qt.LeftButton)
|
||||
|
||||
# It executes the left-click action into object with given object name:
|
||||
def click_obj_by_name(objName: str):
|
||||
obj = squish.waitForObject(getattr(names, objName))
|
||||
# If timeout is 0, it will use the default timeout (testSettings.waitForObjectTimeout)
|
||||
def click_obj_by_name(objName: str, timeout: int=0):
|
||||
if timeout > 0:
|
||||
obj = squish.waitForObject(getattr(names, objName), timeout)
|
||||
else:
|
||||
obj = squish.waitForObject(getattr(names, objName))
|
||||
squish.mouseClick(obj, squish.Qt.LeftButton)
|
||||
|
||||
# It executes the click action into the given object at particular coordinates:
|
||||
@ -184,22 +188,29 @@ def reset_scroll_obj_by_name(objName: str):
|
||||
# execute do_fn until validation_fn returns True or timeout is reached
|
||||
def do_until_validation_with_timeout(do_fn, validation_fn, message: str, timeout_ms: int=_MAX_WAIT_OBJ_TIMEOUT * 2):
|
||||
start_time = time.time()
|
||||
while(not validation_fn()):
|
||||
while True:
|
||||
do_fn()
|
||||
if validation_fn():
|
||||
break
|
||||
if ((time.time() - start_time) * 1000) > timeout_ms:
|
||||
raise Exception("Timeout reached while validating: " + message)
|
||||
do_fn()
|
||||
|
||||
def scroll_item_until_item_is_visible(itemToScrollObjName: str, itemToBeVisibleObjName: str, timeout_ms: int=_MAX_WAIT_OBJ_TIMEOUT * 2):
|
||||
is_item_visible_fn = lambda: is_loaded_visible_and_enabled(itemToBeVisibleObjName, 10)[0]
|
||||
# It seems the underlying squish.waitForObject sometimes takes more than 300 ms to validate the object is visible
|
||||
is_item_visible_fn = lambda: is_loaded_visible_and_enabled(itemToBeVisibleObjName, 500)[0]
|
||||
scroll_item_fn = lambda: scroll_obj_by_name(itemToScrollObjName)
|
||||
do_until_validation_with_timeout(scroll_item_fn, is_item_visible_fn, f'Scrolling {itemToScrollObjName} until {itemToBeVisibleObjName} is visible', timeout_ms)
|
||||
|
||||
def wait_until_item_not_visible_and_enabled(itemObjName: str, timeout_ms: int=2000):
|
||||
is_item_invisible_fn = lambda: not is_loaded_visible_and_enabled(itemObjName, 100)[0]
|
||||
do_until_validation_with_timeout(lambda: time.sleep(0.05), is_item_invisible_fn, f'Waiting until {itemObjName} is not visible', timeout_ms)
|
||||
|
||||
def check_obj_by_name(objName: str):
|
||||
obj = squish.waitForObject(getattr(names, objName))
|
||||
obj.checked = True
|
||||
|
||||
|
||||
def is_text_matching(objName: str, text: str):
|
||||
def is_text_matching(objName: str, text: str, timeout: int=0):
|
||||
try:
|
||||
obj = squish.waitForObject(getattr(names, objName))
|
||||
test.compare(obj.text, text, "Found the following text " + str(obj.text) + " Wanted: " + text)
|
||||
@ -208,6 +219,23 @@ def is_text_matching(objName: str, text: str):
|
||||
print(objName + " is not found, please check app for correct object and update object mapper")
|
||||
return False
|
||||
|
||||
def wait_for_text_matching(objName: str, text: str, timeout: int=0):
|
||||
try:
|
||||
start_time = time.time()
|
||||
time_run_out = False
|
||||
while not time_run_out:
|
||||
obj = squish.waitForObject(getattr(names, objName))
|
||||
if obj.text == text:
|
||||
break
|
||||
if timeout > 0:
|
||||
time_run_out = ((time.time() - start_time) * 1000) > timeout
|
||||
|
||||
test.compare(obj.text, text, f'Found the following text {str(obj.text)} + Wanted: {text} {("; Aborted after " + str(int(time.time() - start_time)) + "s") if time_run_out else ""}')
|
||||
return True
|
||||
except LookupError:
|
||||
print(objName + " is not found, please check app for correct object and update object mapper")
|
||||
return False
|
||||
|
||||
|
||||
def is_text_matching_insensitive(obj, text: str):
|
||||
try:
|
||||
@ -219,7 +247,7 @@ def is_text_matching_insensitive(obj, text: str):
|
||||
|
||||
|
||||
# It types the specified text into the given object (as if the user had used the keyboard):
|
||||
def type(objName: str, text: str):
|
||||
def type_text(objName: str, text: str):
|
||||
try:
|
||||
obj = squish.findObject(getattr(names, objName))
|
||||
squish.type(obj, text)
|
||||
@ -227,17 +255,20 @@ def type(objName: str, text: str):
|
||||
except LookupError:
|
||||
return False
|
||||
|
||||
|
||||
# It types the specified text in the currently focus input (like if the keyboard was typed on)
|
||||
def native_type(text: str):
|
||||
squish.nativeType(text)
|
||||
|
||||
# Wait for the object to appears and
|
||||
# It types the specified text into the given object (as if the user had used the keyboard):
|
||||
def wait_for_object_and_type(objName: str, text: str):
|
||||
# If timeout is 0, it will use the default timeout (testSettings.waitForObjectTimeout)
|
||||
def wait_for_object_and_type(objName: str, text: str, timeout: int=0):
|
||||
try:
|
||||
obj = squish.waitForObject(getattr(names, objName))
|
||||
squish.type(obj, text)
|
||||
if timeout > 0:
|
||||
obj = squish.waitForObject(getattr(names, objName), timeout)
|
||||
else:
|
||||
obj = squish.waitForObject(getattr(names, objName))
|
||||
squish.type(obj, text)
|
||||
return True
|
||||
except LookupError:
|
||||
return False
|
||||
@ -363,3 +394,6 @@ def get_child_item_with_object_name(item, objectName: str):
|
||||
|
||||
def sleep_test(seconds: float):
|
||||
squish.snooze(seconds)
|
||||
|
||||
def wait_for(py_condition_to_check: str, timeout_msec: int = 500):
|
||||
squish.waitFor(py_condition_to_check, timeout_msec)
|
@ -14,9 +14,11 @@ _MIN_WAIT_OBJ_TIMEOUT = 500
|
||||
# The default maximum timeout to wait for close the app in seconds
|
||||
_MAX_WAIT_CLOSE_APP_TIMEOUT = 20
|
||||
|
||||
import traceback
|
||||
|
||||
def verify_screen(objName: str, timeout: int=1000):
|
||||
result = is_loaded_visible_and_enabled(objName, timeout)
|
||||
test.verify(result, True)
|
||||
test.verify(result, f'Verifying screen for real-name {objName}')
|
||||
|
||||
def verify_object_enabled(objName: str, timeout: int=_MIN_WAIT_OBJ_TIMEOUT, condition: bool=True):
|
||||
result = is_loaded_visible_and_enabled(objName, timeout)
|
||||
|
@ -19,6 +19,7 @@ from drivers.SquishDriverVerification import *
|
||||
from utils.ObjectAccess import *
|
||||
from .StatusMainScreen import MainScreenComponents
|
||||
from .StatusMainScreen import StatusMainScreen
|
||||
from .StatusMainScreen import authenticatePopupEnterPassword
|
||||
|
||||
class SettingsScreenComponents(Enum):
|
||||
SAVE_BUTTON: str = "settingsSave_StatusButton"
|
||||
@ -128,18 +129,14 @@ class BackupSeedPhrasePopup(Enum):
|
||||
CONFIRM_SECOND_WORD_INPUT: str = "backup_seed_phrase_popup_BackupSeedStepBase_confirmSecondWord_inputText"
|
||||
CONFIRM_YOU_STORED_CHECKBOX: str = "backup_seed_phrase_popup_ConfirmStoringSeedPhrasePanel_storeCheck"
|
||||
CONFIRM_YOU_STORED_BUTTON: str = "backup_seed_phrase_popup_BackupSeedModal_completeAndDeleteSeedPhraseButton"
|
||||
|
||||
class SharedPopup(Enum):
|
||||
POPUP_CONTENT: str = "sharedPopup_Popup_Content"
|
||||
PASSWORD_INPUT: str = "sharedPopup_Password_Input"
|
||||
PRIMARY_BUTTON: str = "sharedPopup_Primary_Button"
|
||||
|
||||
|
||||
class SettingsScreen:
|
||||
__pid = 0
|
||||
|
||||
|
||||
def __init__(self):
|
||||
verify_screen(SidebarComponents.ADVANCED_OPTION.value)
|
||||
|
||||
|
||||
def open_wallet_settings(self):
|
||||
click_obj_by_name(SidebarComponents.WALLET_OPTION.value)
|
||||
|
||||
@ -150,29 +147,28 @@ class SettingsScreen:
|
||||
verify_object_enabled(SidebarComponents.WALLET_OPTION.value)
|
||||
|
||||
def activate_open_wallet_section(self):
|
||||
self.activate_wallet_option()
|
||||
self.activate_wallet_option()
|
||||
click_obj_by_name(MainScreenComponents.WALLET_BUTTON.value)
|
||||
|
||||
|
||||
def delete_account(self, account_name: str, password: str):
|
||||
self.open_wallet_settings()
|
||||
|
||||
|
||||
index = self._find_account_index(account_name)
|
||||
|
||||
|
||||
if index == -1:
|
||||
raise Exception("Account not found")
|
||||
|
||||
|
||||
accounts = get_obj(WalletSettingsScreen.GENERATED_ACCOUNTS.value)
|
||||
click_obj(accounts.itemAtIndex(index))
|
||||
click_obj_by_name(WalletSettingsScreen.DELETE_ACCOUNT.value)
|
||||
click_obj_by_name(WalletSettingsScreen.DELETE_ACCOUNT_CONFIRM.value)
|
||||
|
||||
wait_for_object_and_type(SharedPopup.PASSWORD_INPUT.value, password)
|
||||
click_obj_by_name(SharedPopup.PRIMARY_BUTTON.value)
|
||||
|
||||
|
||||
authenticatePopupEnterPassword(password)
|
||||
|
||||
def verify_no_account(self, account_name: str):
|
||||
index = self._find_account_index(account_name)
|
||||
verify_equal(index, -1)
|
||||
|
||||
|
||||
def verify_address(self, address: str):
|
||||
accounts = get_obj(WalletSettingsScreen.GENERATED_ACCOUNTS.value)
|
||||
verify_text_matching_insensitive(accounts.itemAtIndex(0).statusListItemSubTitle, address)
|
||||
@ -222,7 +218,7 @@ class SettingsScreen:
|
||||
for _ in range(4):
|
||||
name += string.ascii_lowercase[random.randrange(26)]
|
||||
|
||||
type(ENSScreen.ENS_SEARCH_INPUT.value, name)
|
||||
type_text(ENSScreen.ENS_SEARCH_INPUT.value, name)
|
||||
time.sleep(1)
|
||||
|
||||
click_obj_by_name(ENSScreen.NEXT_BUTTON.value)
|
||||
@ -231,7 +227,7 @@ class SettingsScreen:
|
||||
click_obj_by_name(ENSScreen.TRANSACTION_NEXT_BUTTON.value)
|
||||
click_obj_by_name(ENSScreen.TRANSACTION_NEXT_BUTTON.value)
|
||||
|
||||
type(ENSScreen.PASSWORD_INPUT.value, password)
|
||||
type_text(ENSScreen.PASSWORD_INPUT.value, password)
|
||||
click_obj_by_name(ENSScreen.TRANSACTION_NEXT_BUTTON.value)
|
||||
|
||||
def _find_account_index(self, account_name: str) -> int:
|
||||
@ -255,7 +251,7 @@ class SettingsScreen:
|
||||
click_obj_by_name(WalletSettingsScreen.EDIT_ACCOUNT_BUTTON.value)
|
||||
|
||||
def edit_account(self, account_name: str, account_color: str):
|
||||
type(WalletSettingsScreen.EDIT_ACCOUNT_NAME_INPUT.value, account_name)
|
||||
type_text(WalletSettingsScreen.EDIT_ACCOUNT_NAME_INPUT.value, account_name)
|
||||
colorList = get_obj(WalletSettingsScreen.EDIT_ACCOUNT_COLOR_REPEATER.value)
|
||||
for index in range(colorList.count):
|
||||
color = colorList.itemAt(index)
|
||||
@ -433,11 +429,11 @@ class SettingsScreen:
|
||||
def change_user_password(self, oldPassword: str, newPassword: str):
|
||||
get_and_click_obj(ProfileSettingsScreen.CHANGE_PASSWORD_BUTTON.value)
|
||||
|
||||
type(ChangePasswordMenu.CHANGE_PASSWORD_CURRENT_PASSWORD_INPUT.value, oldPassword)
|
||||
type_text(ChangePasswordMenu.CHANGE_PASSWORD_CURRENT_PASSWORD_INPUT.value, oldPassword)
|
||||
|
||||
type(ChangePasswordMenu.CHANGE_PASSWORD_NEW_PASSWORD_INPUT.value, newPassword)
|
||||
type_text(ChangePasswordMenu.CHANGE_PASSWORD_NEW_PASSWORD_INPUT.value, newPassword)
|
||||
|
||||
type(ChangePasswordMenu.CHANGE_PASSWORD_NEW_PASSWORD_CONFIRM_INPUT.value, newPassword)
|
||||
type_text(ChangePasswordMenu.CHANGE_PASSWORD_NEW_PASSWORD_CONFIRM_INPUT.value, newPassword)
|
||||
|
||||
click_obj_by_name(ChangePasswordMenu.CHANGE_PASSWORD_SUBMIT_BUTTON.value)
|
||||
click_obj_by_name(ChangePasswordMenu.CHANGE_PASSWORD_SUCCESS_MENU_SIGN_OUT_QUIT_BUTTON.value)
|
||||
@ -445,14 +441,14 @@ class SettingsScreen:
|
||||
def add_contact_by_chat_key(self, chat_key: str, who_you_are: str):
|
||||
click_obj_by_name(ContactsViewScreen.CONTACT_REQUEST_CHAT_KEY_BTN.value)
|
||||
|
||||
type(ContactsViewScreen.CONTACT_REQUEST_CHAT_KEY_INPUT.value, chat_key)
|
||||
type(ContactsViewScreen.CONTACT_REQUEST_SAY_WHO_YOU_ARE_INPUT.value, who_you_are)
|
||||
type_text(ContactsViewScreen.CONTACT_REQUEST_CHAT_KEY_INPUT.value, chat_key)
|
||||
type_text(ContactsViewScreen.CONTACT_REQUEST_SAY_WHO_YOU_ARE_INPUT.value, who_you_are)
|
||||
|
||||
click_obj_by_name(ContactsViewScreen.CONTACT_REQUEST_SEND_BUTTON.value)
|
||||
|
||||
def send_contact_request_via_profile_popup(self, who_you_are: str):
|
||||
click_obj_by_name(ProfilePopupScreen.PROFILE_POPUP_SEND_CONTACT_REQUEST_BUTTON.value)
|
||||
type(ProfilePopupScreen.SAY_WHO_YOU_ARE_INPUT.value, who_you_are)
|
||||
type_text(ProfilePopupScreen.SAY_WHO_YOU_ARE_INPUT.value, who_you_are)
|
||||
|
||||
click_obj_by_name(ProfilePopupScreen.SEND_CONTACT_REQUEST_BUTTON.value)
|
||||
|
||||
|
@ -131,7 +131,7 @@ class StatusChatScreen:
|
||||
### Screen actions region:
|
||||
#####################################
|
||||
def type_message(self, message: str):
|
||||
type(ChatComponents.MESSAGE_INPUT.value, message)
|
||||
type_text(ChatComponents.MESSAGE_INPUT.value, message)
|
||||
|
||||
def press_enter(self):
|
||||
press_enter(ChatComponents.MESSAGE_INPUT.value)
|
||||
@ -222,7 +222,7 @@ class StatusChatScreen:
|
||||
move_mouse_over_object(found_edit_button)
|
||||
click_obj(found_edit_button)
|
||||
wait_for_object_and_type(ChatComponents.EDIT_MESSAGE_TEXTAREA.value, "<Ctrl+a>")
|
||||
type(ChatComponents.EDIT_MESSAGE_TEXTAREA.value, message)
|
||||
type_text(ChatComponents.EDIT_MESSAGE_TEXTAREA.value, message)
|
||||
press_enter(ChatComponents.EDIT_MESSAGE_TEXTAREA.value)
|
||||
|
||||
def switch_to_chat(self, chatName: str):
|
||||
|
@ -26,10 +26,10 @@ class StatusCommunityPortalScreen:
|
||||
def create_community(self, communityName: str, communityDescription: str, introMessage: str, outroMessage: str):
|
||||
click_obj_by_name(MainCommunityPortalScreen.CREATE_COMMUNITY_BUTTON.value)
|
||||
|
||||
type(CreateCommunityPopup.COMMUNITY_NAME_INPUT.value, communityName)
|
||||
type(CreateCommunityPopup.COMMUNITY_DESCRIPTION_INPUT.value, communityDescription)
|
||||
type_text(CreateCommunityPopup.COMMUNITY_NAME_INPUT.value, communityName)
|
||||
type_text(CreateCommunityPopup.COMMUNITY_DESCRIPTION_INPUT.value, communityDescription)
|
||||
click_obj_by_name(CreateCommunityPopup.NEXT_SCREEN_BUTTON.value)
|
||||
|
||||
wait_for_object_and_type(CreateCommunityPopup.COMMUNITY_INTRO_MESSAGE_INPUT.value, introMessage)
|
||||
type(CreateCommunityPopup.COMMUNITY_OUTRO_MESSAGE_INPUT.value, outroMessage)
|
||||
type_text(CreateCommunityPopup.COMMUNITY_OUTRO_MESSAGE_INPUT.value, outroMessage)
|
||||
click_obj_by_name(CreateCommunityPopup.DO_CREATE_COMMUNITY_BUTTON.value)
|
||||
|
@ -172,7 +172,7 @@ class StatusCommunityScreen:
|
||||
click_obj_by_name(CommunityScreenComponents.COMMUNITY_CREATE_CHANNEL_MENU_ITEM.value)
|
||||
|
||||
wait_for_object_and_type(CreateOrEditCommunityChannelPopup.COMMUNITY_CHANNEL_NAME_INPUT.value, communityChannelName)
|
||||
type(CreateOrEditCommunityChannelPopup.COMMUNITY_CHANNEL_DESCRIPTION_INPUT.value, communityChannelDescription)
|
||||
type_text(CreateOrEditCommunityChannelPopup.COMMUNITY_CHANNEL_DESCRIPTION_INPUT.value, communityChannelDescription)
|
||||
|
||||
click_obj_by_name(CreateOrEditCommunityChannelPopup.COMMUNITY_CHANNEL_SAVE_OR_CREATE_BUTTON.value)
|
||||
|
||||
@ -181,7 +181,7 @@ class StatusCommunityScreen:
|
||||
|
||||
# Select all text in the input before typing
|
||||
wait_for_object_and_type(CreateOrEditCommunityChannelPopup.COMMUNITY_CHANNEL_NAME_INPUT.value, "<Ctrl+a>")
|
||||
type(CreateOrEditCommunityChannelPopup.COMMUNITY_CHANNEL_NAME_INPUT.value, new_community_channel_name)
|
||||
type_text(CreateOrEditCommunityChannelPopup.COMMUNITY_CHANNEL_NAME_INPUT.value, new_community_channel_name)
|
||||
click_obj_by_name(CreateOrEditCommunityChannelPopup.COMMUNITY_CHANNEL_SAVE_OR_CREATE_BUTTON.value)
|
||||
time.sleep(0.5)
|
||||
|
||||
@ -207,7 +207,7 @@ class StatusCommunityScreen:
|
||||
|
||||
# Select all text in the input before typing
|
||||
wait_for_object_and_type(CreateOrEditCommunityCategoryPopup.COMMUNITY_CATEGORY_NAME_INPUT.value, "<Ctrl+a>")
|
||||
type(CreateOrEditCommunityCategoryPopup.COMMUNITY_CATEGORY_NAME_INPUT.value, new_community_category_name)
|
||||
type_text(CreateOrEditCommunityCategoryPopup.COMMUNITY_CATEGORY_NAME_INPUT.value, new_community_category_name)
|
||||
self._toggle_channels_in_category_popop(community_channel_names)
|
||||
click_obj_by_name(CreateOrEditCommunityCategoryPopup.COMMUNITY_CATEGORY_BUTTON.value)
|
||||
|
||||
@ -249,11 +249,11 @@ class StatusCommunityScreen:
|
||||
def change_community_name(self, new_community_name: str):
|
||||
# Select all text in the input before typing
|
||||
wait_for_object_and_type(CommunitySettingsComponents.EDIT_COMMUNITY_NAME_INPUT.value, "<Ctrl+a>")
|
||||
type(CommunitySettingsComponents.EDIT_COMMUNITY_NAME_INPUT.value, new_community_name)
|
||||
type_text(CommunitySettingsComponents.EDIT_COMMUNITY_NAME_INPUT.value, new_community_name)
|
||||
|
||||
def change_community_description(self, new_community_description: str):
|
||||
wait_for_object_and_type(CommunitySettingsComponents.EDIT_COMMUNITY_DESCRIPTION_INPUT.value, "<Ctrl+a>")
|
||||
type(CommunitySettingsComponents.EDIT_COMMUNITY_DESCRIPTION_INPUT.value, new_community_description)
|
||||
type_text(CommunitySettingsComponents.EDIT_COMMUNITY_DESCRIPTION_INPUT.value, new_community_description)
|
||||
|
||||
def change_community_color(self, new_community_color: str):
|
||||
scroll_obj_by_name(CommunitySettingsComponents.EDIT_COMMUNITY_SCROLL_VIEW.value)
|
||||
@ -262,7 +262,7 @@ class StatusCommunityScreen:
|
||||
|
||||
click_obj_by_name(CommunitySettingsComponents.EDIT_COMMUNITY_COLOR_PICKER_BUTTON.value)
|
||||
wait_for_object_and_type(CommunityColorPanelComponents.HEX_COLOR_INPUT.value, "<Ctrl+a>")
|
||||
type(CommunityColorPanelComponents.HEX_COLOR_INPUT.value, new_community_color)
|
||||
type_text(CommunityColorPanelComponents.HEX_COLOR_INPUT.value, new_community_color)
|
||||
click_obj_by_name(CommunityColorPanelComponents.SAVE_COLOR_BUTTON.value)
|
||||
|
||||
def save_community_changes(self):
|
||||
@ -378,7 +378,7 @@ class StatusCommunityScreen:
|
||||
click_obj(contact_item)
|
||||
click_obj_by_name(CommunityScreenComponents.INVITE_POPUP_NEXT_BUTTON.value)
|
||||
time.sleep(0.5)
|
||||
type(CommunityScreenComponents.INVITE_POPUP_MESSAGE_INPUT.value, message)
|
||||
type_text(CommunityScreenComponents.INVITE_POPUP_MESSAGE_INPUT.value, message)
|
||||
click_obj_by_name(CommunityScreenComponents.INVITE_POPUP_SEND_BUTTON.value)
|
||||
|
||||
def _get_member_obj(self, member_name: str):
|
||||
|
@ -56,7 +56,7 @@ class StatusLoginScreen():
|
||||
|
||||
def enter_password(self, password):
|
||||
click_obj_by_name(SLoginComponents.PASSWORD_INPUT.value)
|
||||
type(SLoginComponents.PASSWORD_INPUT.value, password)
|
||||
type_text(SLoginComponents.PASSWORD_INPUT.value, password)
|
||||
click_obj_by_name(SLoginComponents.SUBMIT_BTN.value)
|
||||
|
||||
def verify_error_message_is_displayed(self):
|
||||
|
@ -42,44 +42,50 @@ class ProfilePopup(Enum):
|
||||
USER_IMAGE = "ProfileHeader_userImage"
|
||||
DISPLAY_NAME = "ProfilePopup_displayName"
|
||||
EDIT_PROFILE_BUTTON = "ProfilePopup_editButton"
|
||||
|
||||
|
||||
class ChatNamePopUp(Enum):
|
||||
CHAT_NAME_TEXT = "chat_name_PlaceholderText"
|
||||
START_CHAT_BTN = "startChat_Btn"
|
||||
|
||||
class SharedPopup(Enum):
|
||||
POPUP_CONTENT: str = "sharedPopup_Popup_Content"
|
||||
PASSWORD_INPUT: str = "sharedPopup_Password_Input"
|
||||
PRIMARY_BUTTON: str = "sharedPopup_Primary_Button"
|
||||
|
||||
def authenticatePopupEnterPassword(password):
|
||||
wait_for_object_and_type(SharedPopup.PASSWORD_INPUT.value, password)
|
||||
click_obj_by_name(SharedPopup.PRIMARY_BUTTON.value)
|
||||
|
||||
class StatusMainScreen:
|
||||
|
||||
def __init__(self):
|
||||
verify_screen(MainScreenComponents.CONTACTS_COLUMN_MESSAGES_HEADLINE.value)
|
||||
|
||||
|
||||
# Main screen is ready to interact with it (Splash screen animation not present)
|
||||
def is_ready(self):
|
||||
self.wait_for_splash_animation_ends()
|
||||
verify(is_displayed(MainScreenComponents.CONTACTS_COLUMN_MESSAGES_HEADLINE.value), "Verifying if the Messages headline is displayed")
|
||||
|
||||
verify(is_displayed(MainScreenComponents.CONTACTS_COLUMN_MESSAGES_HEADLINE.value, 15000), "Verifying if the Messages headline is displayed")
|
||||
|
||||
def wait_for_splash_animation_ends(self, timeoutMSec: int = 10000):
|
||||
start = time.time()
|
||||
[loaded, obj] = is_loaded_visible_and_enabled(MainScreenComponents.SPLASH_SCREEN.value)
|
||||
while loaded and (start + timeoutMSec / 1000 > time.time()):
|
||||
log("Splash screen animation present!")
|
||||
[loaded, obj] = is_loaded_visible_and_enabled(MainScreenComponents.SPLASH_SCREEN.value, 1000)
|
||||
sleep_test(0.5)
|
||||
verify_equal(loaded, False, "Checking splash screen animation has ended.")
|
||||
do_until_validation_with_timeout(
|
||||
do_fn = lambda: time.sleep(0.5),
|
||||
validation_fn = lambda: not is_loaded_visible_and_enabled(MainScreenComponents.SPLASH_SCREEN.value, 1000)[0],
|
||||
message = "Splash screen animation has ended",
|
||||
timeout_ms = timeoutMSec)
|
||||
|
||||
def open_chat_section(self):
|
||||
click_obj_by_name(MainScreenComponents.CHAT_NAVBAR_ICON.value)
|
||||
|
||||
|
||||
def open_community_portal(self):
|
||||
click_obj_by_name(MainScreenComponents.COMMUNITY_PORTAL_BUTTON.value)
|
||||
|
||||
|
||||
def open_settings(self):
|
||||
click_obj_by_name(MainScreenComponents.SETTINGS_BUTTON.value)
|
||||
time.sleep(0.5)
|
||||
|
||||
|
||||
def open_start_chat_view(self):
|
||||
click_obj_by_name(MainScreenComponents.START_CHAT_BTN.value)
|
||||
|
||||
|
||||
def open_chat(self, chatName: str):
|
||||
[loaded, chat_button] = self._find_chat(chatName)
|
||||
if loaded:
|
||||
@ -96,7 +102,7 @@ class StatusMainScreen:
|
||||
for index in range(chat_lists.statusChatListItems.count):
|
||||
chat = chat_lists.statusChatListItems.itemAtIndex(index)
|
||||
if(chat.objectName == chatName):
|
||||
return True, chat
|
||||
return True, chat
|
||||
return False, None
|
||||
|
||||
def open_wallet(self):
|
||||
@ -123,19 +129,19 @@ class StatusMainScreen:
|
||||
def user_is_offline(self):
|
||||
profileButton = squish.waitForObject(getattr(names, MainScreenComponents.PROFILE_NAVBAR_BUTTON.value))
|
||||
verify_equal(profileButton.badge.color.name, "#7f8990", "The user is not offline")
|
||||
|
||||
|
||||
def user_is_set_to_automatic(self):
|
||||
profileButton = squish.waitForObject(getattr(names, MainScreenComponents.PROFILE_NAVBAR_BUTTON.value))
|
||||
verify_equal(profileButton.badge.color.name, "#4ebc60", "The user is not online by default")
|
||||
|
||||
|
||||
def set_user_state_offline(self):
|
||||
click_obj_by_name(MainScreenComponents.PROFILE_NAVBAR_BUTTON.value)
|
||||
click_obj_by_name(MainScreenComponents.USERSTATUSMENU_INACTIVE_ACTION.value)
|
||||
|
||||
|
||||
def set_user_state_online(self):
|
||||
click_obj_by_name(MainScreenComponents.PROFILE_NAVBAR_BUTTON.value)
|
||||
click_obj_by_name(MainScreenComponents.USERSTATUSMENU_ALWAYS_ACTIVE_ACTION.value)
|
||||
|
||||
|
||||
def set_user_state_to_automatic(self):
|
||||
click_obj_by_name(MainScreenComponents.PROFILE_NAVBAR_BUTTON.value)
|
||||
click_obj_by_name(MainScreenComponents.USERSTATUSMENU_AUTOMATIC_ACTION.value)
|
||||
@ -146,21 +152,21 @@ class StatusMainScreen:
|
||||
|
||||
def verify_profile_popup_display_name(self, display_name: str):
|
||||
verify_text_matching(ProfilePopup.DISPLAY_NAME.value, display_name)
|
||||
|
||||
|
||||
def click_escape(self):
|
||||
press_escape(MainScreenComponents.MAIN_WINDOW.value)
|
||||
|
||||
def click_tool_bar_back_button(self):
|
||||
click_obj_by_name(MainScreenComponents.TOOLBAR_BACK_BUTTON.value)
|
||||
press_escape(MainScreenComponents.MAIN_WINDOW.value)
|
||||
|
||||
def click_tool_bar_back_button(self):
|
||||
click_obj_by_name(MainScreenComponents.TOOLBAR_BACK_BUTTON.value)
|
||||
|
||||
def leave_chat(self, chatName: str):
|
||||
[loaded, chat_button] = self._find_chat(chatName)
|
||||
if loaded:
|
||||
right_click_obj(chat_button)
|
||||
hover_and_click_object_by_name(MainScreenComponents.LEAVE_CHAT_MENUITEM.value)
|
||||
|
||||
|
||||
verify(loaded, "Trying to get chat: " + chatName)
|
||||
|
||||
|
||||
def profile_image_is_updated(self):
|
||||
# open profile popup and check image on profileNavBarButton and profileNavBarPopup
|
||||
profileNavBarButton = wait_and_get_obj(MainScreenComponents.PROFILE_NAVBAR_BUTTON.value)
|
||||
@ -168,22 +174,22 @@ class StatusMainScreen:
|
||||
profilePopupImage = wait_and_get_obj(ProfilePopup.USER_IMAGE.value)
|
||||
image_present("loginUserName", True, 95, 75, 100, True, profileNavBarButton)
|
||||
image_present("loginUserName", True, 95, 75, 100, True, profilePopupImage)
|
||||
|
||||
|
||||
def profile_modal_image_is_updated(self):
|
||||
click_obj_by_name(MainScreenComponents.PROFILE_NAVBAR_BUTTON.value)
|
||||
click_obj_by_name(MainScreenComponents.USERSTATUSMENU_OPEN_PROFILE_POPUP.value)
|
||||
image_present("profiletestimage", True, 97, 95, 100, True)
|
||||
|
||||
|
||||
def profile_settings_image_is_updated(self):
|
||||
# first time clicking on settings button closes the my profile modal
|
||||
click_obj_by_name(MainScreenComponents.SETTINGS_BUTTON.value)
|
||||
click_obj_by_name(MainScreenComponents.SETTINGS_BUTTON.value)
|
||||
myProfileSettingsObject = wait_and_get_obj(MainScreenComponents.PROFILE_SETTINGS_VIEW.value)
|
||||
image_present("profiletestimage", True, 95, 100, 183, True, myProfileSettingsObject)
|
||||
|
||||
|
||||
def navigate_to_edit_profile(self):
|
||||
click_obj_by_name(ProfilePopup.EDIT_PROFILE_BUTTON.value)
|
||||
|
||||
|
||||
def close_popup(self):
|
||||
# Click in the corner of the overlay to close the popup
|
||||
click_obj_by_name_at_coordinates(MainScreenComponents.POPUP_OVERLAY.value, 1, 1)
|
||||
|
@ -37,7 +37,7 @@ class StatusSearchScreen:
|
||||
|
||||
def search_for(self, search_term: str):
|
||||
click_obj_by_name(SearchPopupComponents.RESET_BUTTON.value)
|
||||
type(SearchPopupComponents.SEARCH_INPUT.value, search_term)
|
||||
type_text(SearchPopupComponents.SEARCH_INPUT.value, search_term)
|
||||
self.wait_for_loading_done()
|
||||
|
||||
def verify_number_of_results(self, amount: int):
|
||||
|
@ -1,11 +1,12 @@
|
||||
from ast import Tuple
|
||||
from enum import Enum
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
from drivers.SquishDriver import *
|
||||
from drivers.SquishDriverVerification import *
|
||||
from common.SeedUtils import *
|
||||
from .StatusMainScreen import StatusMainScreen
|
||||
from .StatusMainScreen import authenticatePopupEnterPassword
|
||||
from drivers.SquishDriver import type_text as type_text
|
||||
|
||||
class Tokens(Enum):
|
||||
ETH: str = "ETH"
|
||||
@ -67,15 +68,13 @@ class AddAccountPopup(Enum):
|
||||
TYPE_SEED_PHRASE: str = "mainWallet_Add_Account_Popup_Type_Seed_Phrase"
|
||||
TYPE_PRIVATE_KEY: str = "mainWallet_Add_Account_Popup_Type_Private_Key"
|
||||
ADDRESS_INPUT: str = "mainWallet_Add_Account_Popup_Watch_Only_Address"
|
||||
ADDRESS_INPUT_PLACEHOLDER: str = "mainWallet_Add_Account_Popup_Watch_Only_Address_Placeholder"
|
||||
PRIVATE_KEY_INPUT: str = "mainWallet_Add_Account_Popup_Private_Key"
|
||||
ADD_ACCOUNT_BUTTON: str = "mainWallet_Add_Account_Popup_Footer_Add_Account"
|
||||
SEED_PHRASE_INPUT_TEMPLATE: str = "mainWindow_Add_Account_Popup_Seed_Phrase_"
|
||||
SEED_PHRASE_INPUT_LAST: str = "mainWindow_Add_Account_Popup_Seed_Phrase_12"
|
||||
|
||||
class SharedPopup(Enum):
|
||||
POPUP_CONTENT: str = "sharedPopup_Popup_Content"
|
||||
PASSWORD_INPUT: str = "sharedPopup_Password_Input"
|
||||
PRIMARY_BUTTON: str = "sharedPopup_Primary_Button"
|
||||
FULLY_CUSTOM_PATH_CHECKBOX: str = "mainWallet_Add_Account_Popup_Advanced_Accept_Responsibility_Checkbox"
|
||||
ADD_ACCOUNT_POPUP_ROOT: str = "mainWallet_Add_Account_Popup_Root"
|
||||
|
||||
class CollectiblesView(Enum):
|
||||
COLLECTIONS_REPEATER: str = "mainWallet_Collections_Repeater"
|
||||
@ -99,104 +98,97 @@ class StatusWalletScreen:
|
||||
def accept_signing_phrase(self):
|
||||
click_obj_by_name(SigningPhrasePopUp.OK_GOT_IT_BUTTON.value)
|
||||
|
||||
def add_watch_only_account(self, account_name: str, address: str):
|
||||
def add_watch_only_account(self, account_name: str, address: str, password: str):
|
||||
click_obj_by_name(MainWalletScreen.ADD_ACCOUNT_BUTTON.value)
|
||||
|
||||
type(AddAccountPopup.ACCOUNT_NAME_INPUT.value, account_name)
|
||||
type_text(AddAccountPopup.ACCOUNT_NAME_INPUT.value, account_name)
|
||||
|
||||
click_obj_by_name(AddAccountPopup.ADVANCE_SECTION.value)
|
||||
click_obj_by_name(AddAccountPopup.ADVANCE_SECTION.value, 2000)
|
||||
|
||||
click_obj_by_name(AddAccountPopup.TYPE_SELECTOR.value)
|
||||
time.sleep(1)
|
||||
click_obj_by_name(AddAccountPopup.TYPE_WATCH_ONLY.value)
|
||||
# Found that all the involved controls are switching availability states very quickly based on the model data
|
||||
# which makes it almost impossible to do a reliable check for different states, hence the retry for 10 seconds
|
||||
# workaround.
|
||||
# TODO remove workaround to retry after add account modal refactoring
|
||||
max_expected_step_duration_ms = 10000
|
||||
def scroll_and_type_fn():
|
||||
try:
|
||||
click_obj_by_name(AddAccountPopup.TYPE_SELECTOR.value)
|
||||
click_obj_by_name(AddAccountPopup.TYPE_WATCH_ONLY.value)
|
||||
|
||||
scroll_item_until_item_is_visible(AddAccountPopup.SCROLL_BAR.value, AddAccountPopup.ADDRESS_INPUT.value)
|
||||
type(AddAccountPopup.ADDRESS_INPUT.value, address)
|
||||
click_obj_by_name(AddAccountPopup.ADD_ACCOUNT_BUTTON.value)
|
||||
scroll_item_until_item_is_visible(AddAccountPopup.SCROLL_BAR.value, AddAccountPopup.ADDRESS_INPUT_PLACEHOLDER.value, 2000)
|
||||
wait_for_object_and_type(AddAccountPopup.ADDRESS_INPUT_PLACEHOLDER.value, address)
|
||||
except Exception as e:
|
||||
log(f"Expected fail, ignore it for {max_expected_step_duration_ms/1000} seconds; exception {str(e)}")
|
||||
|
||||
do_until_validation_with_timeout(
|
||||
scroll_and_type_fn,
|
||||
lambda: is_loaded_visible_and_enabled(AddAccountPopup.ADDRESS_INPUT.value, 500)[0],
|
||||
timeout_ms=max_expected_step_duration_ms,
|
||||
message="Fill watch only account address")
|
||||
|
||||
click_obj_by_name(AddAccountPopup.ADD_ACCOUNT_BUTTON.value, 2000)
|
||||
|
||||
def import_private_key(self, account_name: str, password: str, private_key: str):
|
||||
click_obj_by_name(MainWalletScreen.ADD_ACCOUNT_BUTTON.value)
|
||||
|
||||
type(AddAccountPopup.ACCOUNT_NAME_INPUT.value, account_name)
|
||||
type_text(AddAccountPopup.ACCOUNT_NAME_INPUT.value, account_name)
|
||||
|
||||
click_obj_by_name(AddAccountPopup.ADVANCE_SECTION.value)
|
||||
click_obj_by_name(AddAccountPopup.TYPE_SELECTOR.value)
|
||||
time.sleep(1)
|
||||
click_obj_by_name(AddAccountPopup.TYPE_PRIVATE_KEY.value)
|
||||
|
||||
scroll_item_until_item_is_visible(AddAccountPopup.SCROLL_BAR.value, AddAccountPopup.PRIVATE_KEY_INPUT.value)
|
||||
type(AddAccountPopup.PRIVATE_KEY_INPUT.value, private_key)
|
||||
type_text(AddAccountPopup.PRIVATE_KEY_INPUT.value, private_key)
|
||||
|
||||
click_obj_by_name(AddAccountPopup.ADD_ACCOUNT_BUTTON.value)
|
||||
|
||||
wait_for_object_and_type(SharedPopup.PASSWORD_INPUT.value, password)
|
||||
click_obj_by_name(SharedPopup.PRIMARY_BUTTON.value)
|
||||
|
||||
time.sleep(1)
|
||||
authenticatePopupEnterPassword(password)
|
||||
|
||||
def import_seed_phrase(self, account_name: str, password: str, mnemonic: str):
|
||||
click_obj_by_name(MainWalletScreen.ADD_ACCOUNT_BUTTON.value)
|
||||
|
||||
type(AddAccountPopup.ACCOUNT_NAME_INPUT.value, account_name)
|
||||
type_text(AddAccountPopup.ACCOUNT_NAME_INPUT.value, account_name)
|
||||
|
||||
click_obj_by_name(AddAccountPopup.ADVANCE_SECTION.value)
|
||||
time.sleep(1)
|
||||
click_obj_by_name(AddAccountPopup.TYPE_SELECTOR.value)
|
||||
time.sleep(1)
|
||||
click_obj_by_name(AddAccountPopup.TYPE_SEED_PHRASE.value)
|
||||
time.sleep(1)
|
||||
|
||||
for i in range(1, 5):
|
||||
scroll_obj_by_name(AddAccountPopup.SCROLL_BAR.value)
|
||||
time.sleep(1)
|
||||
is_loaded_visible_and_enabled(AddAccountPopup.SCROLL_BAR.value, 1000)
|
||||
scroll_item_until_item_is_visible(AddAccountPopup.SCROLL_BAR.value, AddAccountPopup.SEED_PHRASE_INPUT_LAST.value)
|
||||
|
||||
words = mnemonic.split()
|
||||
input_seed_phrase(AddAccountPopup.SEED_PHRASE_INPUT_TEMPLATE.value, words)
|
||||
time.sleep(1)
|
||||
|
||||
click_obj_by_name(AddAccountPopup.ADD_ACCOUNT_BUTTON.value)
|
||||
|
||||
wait_for_object_and_type(SharedPopup.PASSWORD_INPUT.value, password)
|
||||
click_obj_by_name(SharedPopup.PRIMARY_BUTTON.value)
|
||||
|
||||
time.sleep(1)
|
||||
authenticatePopupEnterPassword(password)
|
||||
|
||||
def generate_new_account(self, account_name: str, password: str):
|
||||
click_obj_by_name(MainWalletScreen.ADD_ACCOUNT_BUTTON.value)
|
||||
|
||||
type(AddAccountPopup.ACCOUNT_NAME_INPUT.value, account_name)
|
||||
|
||||
time.sleep(1)
|
||||
type_text(AddAccountPopup.ACCOUNT_NAME_INPUT.value, account_name)
|
||||
|
||||
click_obj_by_name(AddAccountPopup.ADD_ACCOUNT_BUTTON.value)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
wait_for_object_and_type(SharedPopup.PASSWORD_INPUT.value, password)
|
||||
click_obj_by_name(SharedPopup.PRIMARY_BUTTON.value)
|
||||
time.sleep(1)
|
||||
|
||||
def verify_account_name_is_present(self, account_name: str):
|
||||
verify_text_matching(MainWalletScreen.ACCOUNT_NAME.value, account_name)
|
||||
type(AddAccountPopup.ACCOUNT_NAME_INPUT.value, account_name)
|
||||
click_obj_by_name(AddAccountPopup.ADD_ACCOUNT_BUTTON.value)
|
||||
authenticatePopupEnterPassword(password)
|
||||
|
||||
def send_transaction(self, account_name, amount, token, chain_name, password):
|
||||
is_loaded_visible_and_enabled(AssetView.LIST.value, 2000)
|
||||
list = get_obj(AssetView.LIST.value)
|
||||
squish.waitFor("list.count > 0", 60*1000*2)
|
||||
squish.waitFor("float(str(list.itemAtIndex(0).balance)) > 0", 60*1000*2)
|
||||
# LoadingTokenDelegate will be visible until the balance is loaded verify_account_balance_is_positive checks for TokenDelegate
|
||||
do_until_validation_with_timeout(lambda: time.sleep(0.1), lambda: self.verify_account_balance_is_positive(list, "ETH")[0], "Wait for tokens to load", 10000)
|
||||
|
||||
click_obj_by_name(MainWalletScreen.SEND_BUTTON_FOOTER.value)
|
||||
|
||||
self._click_repeater(SendPopup.HEADER_ACCOUNTS_LIST.value, account_name)
|
||||
time.sleep(1)
|
||||
type(SendPopup.AMOUNT_INPUT.value, amount)
|
||||
is_loaded_visible_and_enabled(SendPopup.AMOUNT_INPUT.value, 1000)
|
||||
type_text(SendPopup.AMOUNT_INPUT.value, amount)
|
||||
|
||||
click_obj_by_name(SendPopup.ASSET_SELECTOR.value)
|
||||
asset_list = get_obj(SendPopup.ASSET_LIST.value)
|
||||
for index in range(asset_list.count):
|
||||
tokenObj = asset_list.itemAtIndex(index)
|
||||
if(not squish.isNull(tokenObj) and tokenObj.objectName == "AssetSelector_ItemDelegate_" + token):
|
||||
if(not is_null(tokenObj) and tokenObj.objectName == "AssetSelector_ItemDelegate_" + token):
|
||||
click_obj(asset_list.itemAtIndex(index))
|
||||
break
|
||||
|
||||
@ -210,12 +202,10 @@ class StatusWalletScreen:
|
||||
break
|
||||
|
||||
scroll_obj_by_name(SendPopup.SCROLL_BAR.value)
|
||||
time.sleep(1)
|
||||
|
||||
click_obj_by_name(SendPopup.SEND_BUTTON.value)
|
||||
wait_for_object_and_type(SharedPopup.PASSWORD_INPUT.value, password)
|
||||
|
||||
click_obj_by_name(SharedPopup.PRIMARY_BUTTON.value)
|
||||
authenticatePopupEnterPassword(password)
|
||||
|
||||
def _click_repeater(self, repeater_object_name: str, object_name: str):
|
||||
repeater = get_obj(repeater_object_name)
|
||||
@ -227,8 +217,8 @@ class StatusWalletScreen:
|
||||
def add_saved_address(self, name: str, address: str):
|
||||
click_obj_by_name(MainWalletScreen.SAVED_ADDRESSES_BUTTON.value)
|
||||
click_obj_by_name(SavedAddressesScreen.ADD_BUTTON.value)
|
||||
type(AddSavedAddressPopup.NAME_INPUT.value, name)
|
||||
type(AddSavedAddressPopup.ADDRESS_INPUT.value, address)
|
||||
type_text(AddSavedAddressPopup.NAME_INPUT.value, name)
|
||||
type_text(AddSavedAddressPopup.ADDRESS_INPUT.value, address)
|
||||
click_obj_by_name(AddSavedAddressPopup.ADD_BUTTON.value)
|
||||
|
||||
def _get_saved_address_delegate_item(self, name: str):
|
||||
@ -250,7 +240,7 @@ class StatusWalletScreen:
|
||||
self._find_saved_address_and_open_menu(name)
|
||||
|
||||
click_obj_by_name(SavedAddressesScreen.EDIT.value)
|
||||
type(AddSavedAddressPopup.NAME_INPUT.value, new_name)
|
||||
type_text(AddSavedAddressPopup.NAME_INPUT.value, new_name)
|
||||
click_obj_by_name(AddSavedAddressPopup.ADD_BUTTON.value)
|
||||
|
||||
def delete_saved_address(self, name: str):
|
||||
@ -275,17 +265,16 @@ class StatusWalletScreen:
|
||||
wait_for_prop_value(item, "titleTextIcon", ("star-icon" if favourite else ""))
|
||||
|
||||
def toggle_network(self, network_name: str):
|
||||
time.sleep(2)
|
||||
is_loaded_visible_and_enabled(MainWalletScreen.NETWORK_SELECTOR_BUTTON.value, 2000)
|
||||
click_obj_by_name(MainWalletScreen.NETWORK_SELECTOR_BUTTON.value)
|
||||
time.sleep(2)
|
||||
|
||||
is_loaded_visible_and_enabled(NetworkSelectorPopup.LAYER_1_REPEATER.value, 2000)
|
||||
list = wait_and_get_obj(NetworkSelectorPopup.LAYER_1_REPEATER.value)
|
||||
for index in range(list.count):
|
||||
item = list.itemAt(index)
|
||||
if item.objectName == network_name:
|
||||
click_obj(item)
|
||||
click_obj_by_name(MainWalletScreen.ACCOUNT_NAME.value)
|
||||
time.sleep(2)
|
||||
return
|
||||
|
||||
assert False, "network name not found"
|
||||
@ -299,29 +288,23 @@ class StatusWalletScreen:
|
||||
#####################################
|
||||
|
||||
def verify_account_name_is_present(self, account_name: str):
|
||||
verify_text_matching(MainWalletScreen.ACCOUNT_NAME.value, account_name)
|
||||
# Wait 2 second for UI text to update
|
||||
test.verify(wait_for_text_matching(MainWalletScreen.ACCOUNT_NAME.value, account_name, 2000), "Account name was updated and matches expected")
|
||||
|
||||
def verify_account_balance_is_positive(self, list, symbol: str) -> Tuple(bool, ):
|
||||
if list is None:
|
||||
return (False, )
|
||||
|
||||
for index in range(list.count):
|
||||
tokenListItem = list.itemAtIndex(index)
|
||||
if tokenListItem != None and tokenListItem.objectName == "AssetView_TokenListItem_" + symbol and tokenListItem.balance != "0":
|
||||
return (True, tokenListItem)
|
||||
return (False, )
|
||||
|
||||
def verify_positive_balance(self, symbol: str):
|
||||
time.sleep(5) # TODO: remove when it is faster @alaibe!
|
||||
is_loaded_visible_and_enabled(AssetView.LIST.value, 5000)
|
||||
list = get_obj(AssetView.LIST.value)
|
||||
reset = 0
|
||||
while (reset < 3):
|
||||
found = False
|
||||
for index in range(list.count):
|
||||
tokenListItem = list.itemAtIndex(index)
|
||||
if tokenListItem.objectName == "AssetView_TokenListItem_" + symbol:
|
||||
found = True
|
||||
if (tokenListItem.balance == "0" and reset < 3):
|
||||
break
|
||||
|
||||
return
|
||||
|
||||
if not found:
|
||||
verify_failure("Symbol " + symbol + " not found in the asset list")
|
||||
reset += 1
|
||||
time.sleep(5)
|
||||
|
||||
verify_failure("Balance was not positive")
|
||||
do_until_validation_with_timeout(lambda: time.sleep(0.1), lambda: self.verify_account_balance_is_positive(list, symbol)[0], "Symbol " + symbol + " not found in the asset list", 5000)
|
||||
|
||||
def verify_saved_address_exists(self, name: str):
|
||||
list = wait_and_get_obj(SavedAddressesScreen.SAVED_ADDRESSES_LIST.value)
|
||||
@ -365,7 +348,7 @@ class StatusWalletScreen:
|
||||
|
||||
transaction_list_view = get_obj(TransactionsView.TRANSACTIONS_LISTVIEW.value)
|
||||
|
||||
squish.waitFor("transaction_list_view.count > 0", 60*1000)
|
||||
wait_for("transaction_list_view.count > 0", 60*1000)
|
||||
verify(transaction_list_view.count > 1, "Transactions not retrieved for the account")
|
||||
|
||||
transaction_item = transaction_list_view.itemAtIndex(1)
|
||||
|
@ -43,7 +43,7 @@ class SignUpComponents(Enum):
|
||||
WELCOME_SCREEN_USER_PROFILE_IMAGE: str = "mainWindow_WelcomeScreen_User_Profile_Image"
|
||||
WELCOME_SCREEN_CHAT_KEY_TEXT: str = "mainWindow_WelcomeScreen_ChatKeyText"
|
||||
BACK_BTN: str = "onboarding_back_button"
|
||||
|
||||
|
||||
class SeedPhraseComponents(Enum):
|
||||
IMPORT_A_SEED_TEXT: str = "import_a_seed_phrase_StatusBaseText"
|
||||
INVALID_SEED_TEXT: str = "onboarding_InvalidSeed_Text"
|
||||
@ -53,7 +53,7 @@ class SeedPhraseComponents(Enum):
|
||||
TWENTY_FOUR_BUTTON: str = "switchTabBar_24_words_Button"
|
||||
SEEDS_WORDS_TEXTFIELD_template: str = "onboarding_SeedPhrase_Input_TextField_"
|
||||
SUBMIT_BUTTON: str = "seedPhraseView_Submit_Button"
|
||||
|
||||
|
||||
class PasswordStrengthPossibilities(Enum):
|
||||
LOWER_VERY_WEAK = "lower_very_weak"
|
||||
UPPER_VERY_WEAK = "upper_very_weak"
|
||||
@ -66,7 +66,7 @@ class PasswordStrengthPossibilities(Enum):
|
||||
|
||||
class MainScreen(Enum):
|
||||
SETTINGS_BUTTON = "settings_navbar_settings_icon_StatusIcon"
|
||||
|
||||
|
||||
class LoginView(Enum):
|
||||
LOGIN_VIEW_USER_IMAGE: str = "loginView_userImage"
|
||||
PASSWORD_INPUT = "loginView_passwordInput"
|
||||
@ -97,7 +97,13 @@ class StatusWelcomeScreen:
|
||||
|
||||
def input_seed_phrase(self, seed_phrase: str):
|
||||
words = seed_phrase.split()
|
||||
|
||||
|
||||
# On MacOS, there is an additional step to import a seed phrase than on Linux
|
||||
try:
|
||||
click_obj_by_name(SeedPhraseComponents.IMPORT_A_SEED_BUTTON.value, 1000)
|
||||
except LookupError:
|
||||
log("Ignoring error on non MacOS, as it is expected to not find the import seed phrase button at this stage")
|
||||
|
||||
if len(words) == 12:
|
||||
click_obj_by_name(SeedPhraseComponents.TWELVE_WORDS_BUTTON.value)
|
||||
elif len(words) == 18:
|
||||
@ -124,7 +130,7 @@ class StatusWelcomeScreen:
|
||||
|
||||
def input_username(self, username: str):
|
||||
common.clear_input_text(SignUpComponents.USERNAME_INPUT.value)
|
||||
type(SignUpComponents.USERNAME_INPUT.value, username)
|
||||
type_text(SignUpComponents.USERNAME_INPUT.value, username)
|
||||
click_obj_by_name(SignUpComponents.DETAILS_NEXT_BUTTON.value)
|
||||
|
||||
# The next click will move too fast sometime
|
||||
@ -138,8 +144,8 @@ class StatusWelcomeScreen:
|
||||
|
||||
def input_password(self, password: str):
|
||||
verify(is_loaded_visible_and_enabled(SignUpComponents.NEW_PSW_INPUT.value, 10)[0], 'New Password input is visible')
|
||||
type(SignUpComponents.NEW_PSW_INPUT.value, password)
|
||||
type(SignUpComponents.CONFIRM_PSW_INPUT.value, password)
|
||||
type_text(SignUpComponents.NEW_PSW_INPUT.value, password)
|
||||
type_text(SignUpComponents.CONFIRM_PSW_INPUT.value, password)
|
||||
do_until_validation_with_timeout(
|
||||
do_fn = lambda: click_obj_by_name(SignUpComponents.CREATE_PSW_BUTTON.value),
|
||||
validation_fn = lambda: not is_loaded_visible_and_enabled(SignUpComponents.CREATE_PSW_BUTTON.value, 50)[0],
|
||||
@ -147,7 +153,7 @@ class StatusWelcomeScreen:
|
||||
|
||||
def input_confirmation_password(self, password: str):
|
||||
verify(is_loaded_visible_and_enabled(SignUpComponents.CONFIRM_PSW_AGAIN_INPUT.value, 10)[0], 'Reconfirm password is visible')
|
||||
type(SignUpComponents.CONFIRM_PSW_AGAIN_INPUT.value, password)
|
||||
type_text(SignUpComponents.CONFIRM_PSW_AGAIN_INPUT.value, password)
|
||||
do_until_validation_with_timeout(
|
||||
do_fn = lambda: click_obj_by_name(SignUpComponents.FINALIZE_PSW_BUTTON.value),
|
||||
validation_fn = lambda: not is_loaded_visible_and_enabled(SignUpComponents.FINALIZE_PSW_BUTTON.value, 50)[0],
|
||||
@ -162,10 +168,10 @@ class StatusWelcomeScreen:
|
||||
click_obj_by_name(AgreementPopUp.GET_STARTED_BUTTON.value)
|
||||
verify_text_matching(SignUpComponents.WELCOME_TO_STATUS.value, "Welcome to Status")
|
||||
click_obj_by_name(SignUpComponents.NEW_TO_STATUS.value)
|
||||
|
||||
|
||||
def seed_phrase_visible(self):
|
||||
is_loaded_visible_and_enabled(SeedPhraseComponents.INVALID_SEED_TEXT.value)
|
||||
|
||||
|
||||
# The following validation is based in screenshots comparison and is OS dependent:
|
||||
def validate_password_strength(self, strength: str):
|
||||
if sys.platform == "darwin":
|
||||
@ -192,29 +198,29 @@ class StatusWelcomeScreen:
|
||||
|
||||
elif strength == PasswordStrengthPossibilities.NUMBERS_SYMBOLS_LOWER_UPPER_GREAT.value:
|
||||
verify_screenshot("VP-PWStrength-numbers_symbols_lower_upper_great")
|
||||
|
||||
|
||||
# TODO: Get screenshots in Linux
|
||||
|
||||
def input_profile_image(self, profileImageUrl: str):
|
||||
workflow = get_obj(SignUpComponents.PROFILE_IMAGE_CROP_WORKFLOW_ITEM.value)
|
||||
workflow.cropImage(profileImageUrl)
|
||||
workflow.cropImage(profileImageUrl)
|
||||
click_obj_by_name(SignUpComponents.PROFILE_IMAGE_CROPPER_ACCEPT_BUTTON.value)
|
||||
|
||||
|
||||
def input_username_and_grab_profile_image_sreenshot(self, username: str):
|
||||
type(SignUpComponents.USERNAME_INPUT.value, username)
|
||||
type_text(SignUpComponents.USERNAME_INPUT.value, username)
|
||||
click_obj_by_name(SignUpComponents.DETAILS_NEXT_BUTTON.value)
|
||||
|
||||
|
||||
# take a screenshot of the profile image to compare it later with the main screen
|
||||
profileIcon = wait_and_get_obj(SignUpComponents.WELCOME_SCREEN_USER_PROFILE_IMAGE.value)
|
||||
grabScreenshot_and_save(profileIcon, "profiletestimage", 200)
|
||||
|
||||
|
||||
# There is another page with the same Next button
|
||||
click_obj_by_name(SignUpComponents.DETAILS_NEXT_BUTTON.value)
|
||||
|
||||
def input_username_profileImage_password_and_finalize_sign_up(self, profileImageUrl: str, username: str, password: str):
|
||||
self.input_profile_image(profileImageUrl)
|
||||
|
||||
self.input_username_and_grab_profile_image_sreenshot(username)
|
||||
self.input_username_and_grab_profile_image_sreenshot(username)
|
||||
|
||||
self.input_password(password)
|
||||
|
||||
@ -222,17 +228,17 @@ class StatusWelcomeScreen:
|
||||
|
||||
if sys.platform == "darwin":
|
||||
click_obj_by_name(SignUpComponents.PASSWORD_PREFERENCE.value)
|
||||
|
||||
|
||||
def grab_screenshot(self):
|
||||
# take a screenshot of the profile image to compare it later with the main screen
|
||||
loginUserName = wait_and_get_obj(LoginView.LOGIN_VIEW_USER_IMAGE.value)
|
||||
grabScreenshot_and_save(loginUserName, "loginUserName", 200)
|
||||
|
||||
|
||||
def enter_password(self, password):
|
||||
click_obj_by_name(LoginView.PASSWORD_INPUT.value)
|
||||
type(LoginView.PASSWORD_INPUT.value, password)
|
||||
click_obj_by_name(LoginView.SUBMIT_BTN.value)
|
||||
|
||||
type_text(LoginView.PASSWORD_INPUT.value, password)
|
||||
click_obj_by_name(LoginView.SUBMIT_BTN.value)
|
||||
|
||||
def navigate_back_to_user_profile_page(self):
|
||||
count = 0
|
||||
while not is_displayed(SignUpComponents.USERNAME_INPUT.value, 500):
|
||||
|
@ -38,7 +38,7 @@ Feature: Status Desktop Sign Up
|
||||
| lemon card easy goose keen divide cabbage daughter glide glad sense dice promote present august obey stay cheese | 0xdd06a08d469dd61Cb2E5ECE30f5D16019eBe0fc9 |
|
||||
| provide between target maze travel enroll edge churn random sight grass lion diet sugar cable fiction reflect reason gaze camp tone maximum task unlock | 0xCb59031d11D233112CB57DFd667fE1FF6Cd7b6Da |
|
||||
|
||||
|
||||
@mayfail
|
||||
Scenario: The user signs up with a profile image
|
||||
Given A first time user lands on the status desktop and generates new key
|
||||
And the user signs up with profileImage "doggo.jpeg", username "tester123" and password "TesTEr16843/!@00"
|
||||
|
@ -40,12 +40,14 @@ mainWallet_Send_Popup_GasPrice_Input = {"container": statusDesktop_mainWindow, "
|
||||
mainWallet_Add_Account_Popup_Main = {"container": statusDesktop_mainWindow, "objectName": "AddAccountModalContent", "type": "StatusScrollView", "visible": True}
|
||||
mainWallet_Add_Account_Popup_Password = {"container": mainWallet_Add_Account_Popup_Main, "text": "Enter your password...", "type": "PlaceholderText", "unnamed": 1, "visible": True}
|
||||
mainWallet_Add_Account_Popup_Advanced = {"container": mainWallet_Add_Account_Popup_Main, "objectName": "ExpandableItem", "type": "MouseArea", "visible": True}
|
||||
mainWallet_Add_Account_Popup_Type_Selector = {"container": mainWallet_Add_Account_Popup_Main, "text": "Default", "type": "StatusBaseText", "unnamed": 1, "visible": True}
|
||||
mainWallet_Add_Account_Popup_Type_Watch_Only = {"container": statusDesktop_mainWindow, "text": "Add a watch-only address", "type": "StatusBaseText", "unnamed": 1, "visible": True}
|
||||
mainWallet_Add_Account_Popup_Type_Private_Key = {"container": statusDesktop_mainWindow, "text": "Generate from Private key", "type": "StatusBaseText", "unnamed": 1, "visible": True}
|
||||
mainWallet_Add_Account_Popup_Type_Seed_Phrase = {"container": statusDesktop_mainWindow, "text": "Import new Seed Phrase", "type": "StatusBaseText", "unnamed": 1, "visible": True}
|
||||
mainWallet_Add_Account_Popup_Type_Selector = {"container": mainWallet_Add_Account_Popup_Main, "objectName": "selectGeneratedAccount", "type": "SelectGeneratedAccount", "visible": True}
|
||||
mainWallet_Add_Account_Popup_Type_Watch_Only = {"container": statusDesktop_mainWindow, "objectName": "watchOnlyAccount", "type": "StatusListItem", "visible": True}
|
||||
mainWallet_Add_Account_Popup_Type_Private_Key = {"container": statusDesktop_mainWindow, "objectName": "generateFromPrivateKey", "type": "StatusListItem", "visible": True}
|
||||
mainWallet_Add_Account_Popup_Type_Seed_Phrase = {"container": statusDesktop_mainWindow, "objectName": "importNewSeedPhrase", "type": "StatusListItem", "visible": True}
|
||||
mainWallet_Add_Account_Popup_Account_Name = {"container": mainWallet_Add_Account_Popup_Main, "text": "Enter an account name...", "type": "StatusBaseText", "unnamed": 1, "visible": True}
|
||||
mainWallet_Add_Account_Popup_Watch_Only_Address = {"container": mainWallet_Add_Account_Popup_Main, "text": "Enter address...", "type": "StatusBaseText", "unnamed": 1, "visible": True}
|
||||
mainWallet_Add_Account_Popup_Root = {"container": mainWallet_Add_Account_Popup_Main, "objectName": "advancedAddAccountViewRoot", "type": "AdvancedAddAccountView", "visible": True}
|
||||
mainWallet_Add_Account_Popup_Watch_Only_Address = {"container": mainWallet_Add_Account_Popup_Main, "objectName": "advancedAddAccountViewAddressInput", "type": "StatusBaseInput", "visible": True}
|
||||
mainWallet_Add_Account_Popup_Watch_Only_Address_Placeholder = {"container": mainWallet_Add_Account_Popup_Main, "objectName": "advancedAddAccountViewAddressInputPlaceholder", "type": "StatusBaseText", "visible": True}
|
||||
mainWallet_Add_Account_Popup_Private_Key = {"container": mainWallet_Add_Account_Popup_Main, "text": "Paste the contents of your private key", "type": "StatusBaseText", "unnamed": 1, "visible": True}
|
||||
mainWindow_Add_Account_Popup_Seed_Phrase_1 = {"container": mainWallet_Add_Account_Popup_Main, "type": "StatusBaseText", "objectName": "seedPhraseInputPlaceholder0", "visible": True}
|
||||
mainWindow_Add_Account_Popup_Seed_Phrase_2 = {"container": mainWallet_Add_Account_Popup_Main, "type": "StatusBaseText", "objectName": "seedPhraseInputPlaceholder1", "visible": True}
|
||||
@ -59,6 +61,7 @@ mainWindow_Add_Account_Popup_Seed_Phrase_9 = {"container": mainWallet_Add_Accoun
|
||||
mainWindow_Add_Account_Popup_Seed_Phrase_10 = {"container": mainWallet_Add_Account_Popup_Main, "type": "StatusBaseText", "objectName": "seedPhraseInputPlaceholder9", "visible": True}
|
||||
mainWindow_Add_Account_Popup_Seed_Phrase_11 = {"container": mainWallet_Add_Account_Popup_Main, "type": "StatusBaseText", "objectName": "seedPhraseInputPlaceholder10", "visible": True}
|
||||
mainWindow_Add_Account_Popup_Seed_Phrase_12 = {"container": mainWallet_Add_Account_Popup_Main, "type": "StatusBaseText", "objectName": "seedPhraseInputPlaceholder11", "visible": True}
|
||||
mainWallet_Add_Account_Popup_Advanced_Accept_Responsibility_Checkbox = {"container": mainWallet_Add_Account_Popup_Main, "objectName": "fullyCustomPathCheckBox", "type": "StatusCheckBox", "visible": True}
|
||||
|
||||
mainWallet_Add_Account_Popup_Footer = {"container": statusDesktop_mainWindow, "type": "StatusModalFooter", "unnamed": 1, "visible": True}
|
||||
mainWallet_Authenticate_Popup_Footer_Add_Account = {"container": mainWallet_Add_Account_Popup_Footer, "text": "Authenticate", "type": "StatusBaseText", "unnamed": 1, "visible": True}
|
||||
@ -82,7 +85,7 @@ mainWallet_Collectibles_Repeater = {"container": statusDesktop_mainWindow, "obje
|
||||
|
||||
# Shared Popup
|
||||
sharedPopup_Popup_Content = {"container": statusDesktop_mainWindow, "objectName": "KeycardSharedPopupContent", "type": "Item"}
|
||||
sharedPopup_Password_Input = {"container": sharedPopup_Popup_Content, "objectName": "Password", "type": "TextField"}
|
||||
sharedPopup_Password_Input = {"container": sharedPopup_Popup_Content, "objectName": "keycardPasswordInput", "type": "TextField"}
|
||||
sharedPopup_Primary_Button = {"container": statusDesktop_mainWindow, "objectName": "PrimaryButton", "type": "StatusButton"}
|
||||
|
||||
# Transactions view
|
||||
|
@ -28,10 +28,10 @@ def step(context):
|
||||
### ACTIONS region:
|
||||
#########################
|
||||
|
||||
@When("the user adds watch only account \"|any|\" named \"|any|\"")
|
||||
@When("the user adds watch only account \"|any|\" named \"|any|\" and authenticated using password \"|any|\"")
|
||||
@verify_screenshot
|
||||
def step(context, address, account_name):
|
||||
_walletScreen.add_watch_only_account(account_name, address)
|
||||
def step(context, address, account_name, root_password):
|
||||
_walletScreen.add_watch_only_account(account_name, address, root_password)
|
||||
|
||||
@When("an account named \"|any|\" is generated and authenticated using password \"|any|\"")
|
||||
def step(context, account_name, password):
|
||||
@ -39,11 +39,11 @@ def step(context, account_name, password):
|
||||
|
||||
@When("an account named \"|any|\" is added via private key \"|any|\" and authenticated using password \"|any|\"")
|
||||
def step(context, account_name, private_key, password):
|
||||
_walletScreen.import_private_key(account_name, password, private_key)
|
||||
_walletScreen.import_private_key(account_name, password, private_key)
|
||||
|
||||
@When("an account named \"|any|\" is added via imported seed phrase \"|any|\" and authenticated using password \"|any|\"")
|
||||
@When("an account named \"|any|\" is added via imported seed phrase \"|any|\" and authenticated using password \"|any|\"")
|
||||
def step(context, account_name, mnemonic, password):
|
||||
_walletScreen.import_seed_phrase(account_name, password, mnemonic)
|
||||
_walletScreen.import_seed_phrase(account_name, password, mnemonic)
|
||||
|
||||
@When("the user sends a transaction to himself from account \"|any|\" of \"|any|\" \"|any|\" on \"|any|\" with password \"|any|\"")
|
||||
def step(context, account_name, amount, token, chain_name, password):
|
||||
|
@ -16,7 +16,6 @@ Feature: Status Desktop Transaction
|
||||
** and the user opens wallet screen
|
||||
** and the user accepts the signing phrase
|
||||
|
||||
@mayfail
|
||||
Scenario Outline: The user sends a transaction
|
||||
When the user sends a transaction to himself from account "Status account" of "<amount>" "<token>" on "<chain_name>" with password "qqqqqqqqqq"
|
||||
Then the transaction is in progress
|
||||
@ -24,9 +23,9 @@ Feature: Status Desktop Transaction
|
||||
Examples:
|
||||
| amount | token | chain_name |
|
||||
| 0.1 | ETH | Ethereum Mainnet |
|
||||
#| 0 | ETH | Goerli |
|
||||
#| 1 | STT | Goerli |
|
||||
#| 0 | STT | Goerli |
|
||||
# | 1 | ETH | Goerli |
|
||||
# | 1 | STT | Goerli |
|
||||
# | 100 | STT | Goerli |
|
||||
|
||||
@mayfail
|
||||
Scenario: The user registers an ENS name
|
||||
|
@ -2,7 +2,7 @@ Feature: Status Desktop Wallet
|
||||
|
||||
As a user I want to use the wallet
|
||||
|
||||
The feature start sequence is the following (setup on its own `bdd_hooks`):
|
||||
The feature start sequence is the following (setup on its own `bdd_hooks`):
|
||||
|
||||
** given A first time user lands on the status desktop and generates new key
|
||||
** when user signs up with username "tester123" and password "TesTEr16843/!@00"
|
||||
@ -17,33 +17,28 @@ Feature: Status Desktop Wallet
|
||||
Given the user opens wallet screen
|
||||
And the user clicks on the first account
|
||||
|
||||
@mayfail
|
||||
Scenario: The user can manage and observe a watch only account
|
||||
When the user adds watch only account "0xea123F7beFF45E3C9fdF54B324c29DBdA14a639A" named "AccountWatch"
|
||||
Scenario: The user can manage and observe a watch only account
|
||||
When the user adds watch only account "0xea123F7beFF45E3C9fdF54B324c29DBdA14a639A" named "AccountWatch" and authenticated using password "TesTEr16843/!@00"
|
||||
Then the new account "AccountWatch" is added
|
||||
And the user has a positive balance of "ETH"
|
||||
And the user has a positive balance of "ETH"
|
||||
And the user has a positive balance of "SNT"
|
||||
# And the collectibles are listed for the on
|
||||
# And the transactions are listed for the added account
|
||||
# And the collectibles are listed for the on
|
||||
# And the transactions are listed for the added account
|
||||
|
||||
@mayfail
|
||||
Scenario: The user imports a private key
|
||||
When an account named "AccountPrivate" is added via private key "8da4ef21b864d2cc526dbdb2a120bd2874c36c9d0a1fb7f8c63d7f7a8b41de8f" and authenticated using password "TesTEr16843/!@00"
|
||||
Then the new account "AccountPrivate" is added
|
||||
|
||||
@mayfail
|
||||
Scenario: The user generates a new account from wallet and deletes it
|
||||
Scenario: The user generates a new account from wallet and deletes it
|
||||
When an account named "AccountGenerated" is generated and authenticated using password "TesTEr16843/!@00"
|
||||
Then the new account "AccountGenerated" is added
|
||||
When the user deletes the account "AccountGenerated" with password "TesTEr16843/!@00"
|
||||
Then the account "AccountGenerated" is not in the list of accounts
|
||||
|
||||
@mayfail
|
||||
Scenario: The user can import seed phrase
|
||||
Scenario: The user can import seed phrase
|
||||
When an account named "AccountSeed" is added via imported seed phrase "pelican chief sudden oval media rare swamp elephant lawsuit wheat knife initial" and authenticated using password "TesTEr16843/!@00"
|
||||
Then the new account "AccountSeed" is added
|
||||
|
||||
@mayfail
|
||||
Scenario: The user edits the default account
|
||||
Given the user opens app settings screen
|
||||
And the user opens the wallet settings
|
||||
@ -51,7 +46,6 @@ Feature: Status Desktop Wallet
|
||||
And the user edits default account to "Default" name and "#FFCA0F" color
|
||||
Then the default account is updated to be named "DefaultStatus account" with color "#FFCA0F"
|
||||
|
||||
@mayfail
|
||||
Scenario Outline: The user can manage a saved address
|
||||
When the user adds a saved address named "<name>" and address "<address>"
|
||||
And the user toggles favourite for the saved address with name "<name>"
|
||||
@ -63,6 +57,6 @@ Feature: Status Desktop Wallet
|
||||
When the user adds a saved address named "<name>" and address "<address>"
|
||||
And the user edits a saved address with name "<name>" to "<new_name>"
|
||||
Then the name "<new_name><name>" is in the list of saved addresses
|
||||
Examples:
|
||||
| name | address | new_name |
|
||||
| bar | 0x8397bc3c5a60a1883174f722403d63a8833312b7 | foo |
|
||||
Examples:
|
||||
| name | address | new_name |
|
||||
| bar | 0x8397bc3c5a60a1883174f722403d63a8833312b7 | foo |
|
@ -34,9 +34,9 @@ StatusSelect {
|
||||
|
||||
QtObject {
|
||||
id: _internal
|
||||
property string importSeedPhraseString : qsTr("Import new Seed Phrase")
|
||||
property string importPrivateKeyString : qsTr("Generate from Private key")
|
||||
property string addWatchOnlyAccountString : qsTr("Add a watch-only address")
|
||||
property string importSeedPhraseID: "importNewSeedPhrase"
|
||||
property string importPrivateKeyID: "generateFromPrivateKey"
|
||||
property string addWatchOnlyAccountID: "watchOnlyAccount"
|
||||
|
||||
property var delegateModel: DelegateModel {
|
||||
model: RootStore.generatedAccountsViewModel
|
||||
@ -60,9 +60,9 @@ StatusSelect {
|
||||
}
|
||||
}
|
||||
generatedAccountsModel.append({"name": qsTr("Add new"), "iconName": "", "derivedfrom": "", "isHeader": true, "keyUid": "", "migratedToKeycard": false})
|
||||
generatedAccountsModel.append({"name": _internal.importSeedPhraseString, "iconName": "seed-phrase", "derivedfrom": "", "isHeader": false, "keyUid": "", "migratedToKeycard": false})
|
||||
generatedAccountsModel.append({"name": _internal.importPrivateKeyString, "iconName": "password", "derivedfrom": "", "isHeader": false, "keyUid": "", "migratedToKeycard": false})
|
||||
generatedAccountsModel.append({"name": _internal.addWatchOnlyAccountString, "iconName": "show", "derivedfrom": "", "isHeader": false, "keyUid": "", "migratedToKeycard": false})
|
||||
generatedAccountsModel.append({"name": qsTr("Import new Seed Phrase"), "iconName": "seed-phrase", "derivedfrom": "", "isHeader": false, "keyUid": "", "migratedToKeycard": false, "objectName": _internal.importSeedPhraseID})
|
||||
generatedAccountsModel.append({"name": qsTr("Generate from Private key"), "iconName": "password", "derivedfrom": "", "isHeader": false, "keyUid": "", "migratedToKeycard": false, "objectName": _internal.importPrivateKeyID})
|
||||
generatedAccountsModel.append({"name": qsTr("Add a watch-only address"), "iconName": "show", "derivedfrom": "", "isHeader": false, "keyUid": "", "migratedToKeycard": false, "objectName": _internal.addWatchOnlyAccountID})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -89,6 +89,7 @@ StatusSelect {
|
||||
}
|
||||
menuDelegate: StatusListItem {
|
||||
id: defaultListItem
|
||||
objectName: !!model.objectName ? model.objectName : ""
|
||||
title: model.name
|
||||
asset.name: model.iconName
|
||||
tagsModel : model.generatedModel
|
||||
@ -108,9 +109,9 @@ StatusSelect {
|
||||
titleText.color: Theme.palette.indirectColor1
|
||||
}
|
||||
onClicked: {
|
||||
selectAccountType.addAccountType = (model.name === _internal.importSeedPhraseString) ? Constants.AddAccountType.ImportSeedPhrase :
|
||||
(model.name === _internal.importPrivateKeyString) ? Constants.AddAccountType.ImportPrivateKey :
|
||||
(model.name === _internal.addWatchOnlyAccountString) ? Constants.AddAccountType.WatchOnly :
|
||||
selectAccountType.addAccountType = (model.objectName === _internal.importSeedPhraseID) ? Constants.AddAccountType.ImportSeedPhrase :
|
||||
(model.objectName === _internal.importPrivateKeyID) ? Constants.AddAccountType.ImportPrivateKey :
|
||||
(model.objectName === _internal.addWatchOnlyAccountID) ? Constants.AddAccountType.WatchOnly :
|
||||
Constants.AddAccountType.GenerateNew
|
||||
selectedItem.title = model.name
|
||||
selectedItem.asset.name = model.iconName
|
||||
|
@ -92,17 +92,17 @@ StatusModal {
|
||||
|
||||
function getDerivedAddressList() {
|
||||
if (d.useFullyCustomPath) {
|
||||
if(d.selectedAccountType === Constants.AddAccountType.ImportSeedPhrase
|
||||
&& !!advancedSelection.expandableItem.path
|
||||
&& !!advancedSelection.expandableItem.mnemonicText) {
|
||||
RootStore.getDerivedAddressListForMnemonic(advancedSelection.expandableItem.mnemonicText,
|
||||
advancedSelection.expandableItem.path, numOfItems, pageNumber)
|
||||
} else if(!!d.selectedPath && !!d.selectedAccountDerivedFromAddress
|
||||
if(!!d.selectedPath && !!d.selectedAccountDerivedFromAddress
|
||||
&& (d.password.length > 0)) {
|
||||
RootStore.getDerivedAddressList(d.password, d.selectedAccountDerivedFromAddress,
|
||||
d.selectedPath, numOfItems, pageNumber,
|
||||
!(d.selectedKeyUidMigratedToKeycard || userProfile.isKeycardUser))
|
||||
}
|
||||
} else if(d.selectedAccountType === Constants.AddAccountType.ImportSeedPhrase
|
||||
&& !!advancedSelection.expandableItem.path
|
||||
&& !!advancedSelection.expandableItem.mnemonicText) {
|
||||
RootStore.getDerivedAddressListForMnemonic(advancedSelection.expandableItem.mnemonicText,
|
||||
advancedSelection.expandableItem.path, numOfItems, pageNumber)
|
||||
} else if(!!d.selectedPath && !!d.selectedAccountDerivedFromAddress
|
||||
&& (d.password.length > 0)) {
|
||||
RootStore.getDerivedAddress(d.password, d.selectedAccountDerivedFromAddress, d.selectedPath,
|
||||
@ -334,11 +334,10 @@ StatusModal {
|
||||
return qsTr("Add account")
|
||||
}
|
||||
|
||||
|
||||
enabled: {
|
||||
if (!accountNameInput.valid ||
|
||||
loading ||
|
||||
(!d.useFullyCustomPath && !d.selectedAddressAvailable)) {
|
||||
((root.authenticationNeeded && !d.useFullyCustomPath) && !d.selectedAddressAvailable)) {
|
||||
return false
|
||||
}
|
||||
return advancedSelection.isValid
|
||||
|
@ -37,6 +37,8 @@ ColumnLayout {
|
||||
signal calculateDerivedPath()
|
||||
signal enterPressed()
|
||||
|
||||
objectName: "advancedAddAccountViewRoot"
|
||||
|
||||
function reset() {
|
||||
//reset selectGeneratedAccount
|
||||
selectGeneratedAccount.resetMe()
|
||||
@ -103,6 +105,7 @@ ColumnLayout {
|
||||
|
||||
SelectGeneratedAccount {
|
||||
id: selectGeneratedAccount
|
||||
objectName: "selectGeneratedAccount"
|
||||
Component.onCompleted: {
|
||||
advancedSection.addAccountType = Qt.binding(function() {return addAccountType})
|
||||
advancedSection.derivedFromAddress = Qt.binding(function() {return derivedFromAddress})
|
||||
@ -133,6 +136,8 @@ ColumnLayout {
|
||||
|
||||
StatusInput {
|
||||
id: addressInput
|
||||
input.placeholder.objectName: "advancedAddAccountViewAddressInputPlaceholder"
|
||||
input.objectName: "advancedAddAccountViewAddressInput"
|
||||
visible: advancedSection.addAccountType === Constants.AddAccountType.WatchOnly && advancedSection.visible
|
||||
placeholderText: qsTr("Enter address...")
|
||||
label: qsTr("Account address")
|
||||
@ -160,7 +165,7 @@ ColumnLayout {
|
||||
|
||||
readonly property int itemWidth: (advancedSection.width - Style.current.bigPadding) * 0.5
|
||||
|
||||
DerivationPathsPanel {
|
||||
DerivationPathsPanel {
|
||||
id: derivationPathsPanel
|
||||
useFullyCustomPath: fullyCustomPathCheckBox.checked
|
||||
Layout.preferredWidth: parent.itemWidth
|
||||
@ -187,6 +192,8 @@ ColumnLayout {
|
||||
|
||||
StatusCheckBox {
|
||||
id: fullyCustomPathCheckBox
|
||||
objectName: "fullyCustomPathCheckBox"
|
||||
visible: advancedSection.addAccountType === Constants.AddAccountType.GenerateNew
|
||||
Layout.preferredWidth: advancedSection.width
|
||||
text: qsTr("I acknowledge that by adding an account out of the default Status derivation path I will not be able to migrate a keypair to a Keycard")
|
||||
onToggled: {
|
||||
|
@ -79,7 +79,7 @@ Item {
|
||||
|
||||
StatusPasswordInput {
|
||||
id: password
|
||||
objectName: "Password"
|
||||
objectName: "keycardPasswordInput"
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
signingPhrase: root.sharedKeycardModule.getSigningPhrase()
|
||||
placeholderText: qsTr("Password")
|
||||
|
Loading…
x
Reference in New Issue
Block a user