tests(Settings): Can backup seed phrase

Added debug helpers found useful in debugging while implementing squish
tests

Closes: #6902
This commit is contained in:
Stefan 2022-08-16 18:35:10 +02:00 committed by Stefan Dunca
parent 52bf39af2a
commit f2615e3cef
12 changed files with 137 additions and 9 deletions

View File

@ -128,6 +128,16 @@ def click_obj_by_wildcards_name(objName: str, wildcardString: str):
obj = squish.waitForObject(wildcardRealName)
squish.mouseClick(obj, squish.Qt.LeftButton)
# Replaces all occurrences of objectNamePlaceholder with newValue in the objectName from the realName
# Then use the new objectName as a wildcard search pattern, waiting for the object with the new Real Name
# and return it if found. Raise an exception if not found.
def wait_by_wildcards(realNameVarName: str, objectNamePlaceholder: str, newValue: str, timeoutMSec: int = _MAX_WAIT_OBJ_TIMEOUT):
wildcardRealName = copy.deepcopy(getattr(names, realNameVarName))
newObjectName = wildcardRealName["objectName"].replace(objectNamePlaceholder, newValue)
wildcardRealName["objectName"] = Wildcard(newObjectName)
return squish.waitForObject(wildcardRealName, timeoutMSec)
# It executes the right-click action into object with given object name:
def right_click_obj_by_name(objName: str):
obj = squish.waitForObject(getattr(names, objName))
@ -243,7 +253,7 @@ def _find_link(objName: str, link: str):
squish.uninstallSignalHandler(obj, "linkHovered(QString)", "_handle_link_hovered")
return [-1, -1]
def expectTrue(assertionValue: bool, message: str):
def expect_true(assertionValue: bool, message: str):
return test.verify(assertionValue, message)
# Wait for the object to appear and, assuming it is already focused
@ -274,3 +284,11 @@ def scroll_list_view_at_index(list_obj, index: int, timeout: int=_MAX_WAIT_OBJ_T
squish.snooze(1)
current_time = time.time() * 1000
return False
# Fail if the object is found and pass if not found
def verify_not_found(realNameVarName: str, message: str, timeoutMSec: int = 500):
try:
squish.waitForObject(getattr(names, realNameVarName), timeoutMSec)
test.fail(message, f'Unexpected: the object "{realNameVarName}" was found.')
except LookupError as err:
test.passes(message, f'Expected: the object "{realNameVarName}" was not found. Exception: {str(err)}.')

View File

@ -55,6 +55,7 @@ class WalletSettingsScreen(Enum):
EDIT_ACCOUNT_SAVE_BUTTON: str = "settings_Wallet_AccountView_EditAccountSaveButton"
ACCOUNT_VIEW_ACCOUNT_NAME: str = "settings_Wallet_AccountView_AccountName"
ACCOUNT_VIEW_ICON_SETTINGS: str = "settings_Wallet_AccountView_IconSettings"
BACKUP_SEED_PHRASE_BUTTON: str = "settings_Wallet_MainView_BackupSeedPhrase"
class ProfileSettingsScreen(Enum):
DISPLAY_NAME: str = "displayName_TextEdit"
@ -75,6 +76,20 @@ class CommunitiesSettingsScreen(Enum):
LEAVE_COMMUNITY_BUTTONS: str = "settings_Communities_MainView_LeaveCommunityButtons"
LEAVE_COMMUNITY_POPUP_LEAVE_BUTTON: str = "settings_Communities_MainView_LeavePopup_LeaveCommunityButton"
class BackupSeedPhrasePopup(Enum):
HAVE_PEN_CHECKBOX: str = "backup_seed_phrase_popup_Acknowledgements_havePen_checkbox"
WRITE_DOWN_CHECKBOX: str = "backup_seed_phrase_popup_Acknowledgements_writeDown_checkbox"
STORE_IT_CHECKBOX: str = "backup_seed_phrase_popup_Acknowledgements_storeIt_checkbox"
NEXT_BUTTON: str = "backup_seed_phrase_popup_nextButton"
REVEAL_SEED_PHRASE_BUTTON: str = "backup_seed_phrase_popup_ConfirmSeedPhrasePanel_RevealSeedPhraseButton"
SEED_PHRASE_WORD_PLACEHOLDER: str = "backup_seed_phrase_popup_ConfirmSeedPhrasePanel_StatusSeedPhraseInput_placeholder"
CONFIRM_FIRST_WORD_PAGE: str = "backup_seed_phrase_popup_BackupSeedStepBase_confirmFirstWord"
CONFIRM_FIRST_WORD_INPUT: str = "backup_seed_phrase_popup_BackupSeedStepBase_confirmFirstWord_inputText"
CONFIRM_SECOND_WORD_PAGE: str = "backup_seed_phrase_popup_BackupSeedStepBase_confirmSecondWord"
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 SettingsScreen:
__pid = 0
@ -244,3 +259,44 @@ class SettingsScreen:
verify_text_matching(ProfileSettingsScreen.CUSTOM_LINK_IN_DIALOG.value, custom_link_name)
verify_text_matching(ProfileSettingsScreen.CUSTOM_URL_IN_DIALOG.value, custom_link)
click_obj_by_name(ProfileSettingsScreen.CLOSE_SOCIAL_LINKS_DIALOG.value)
def check_backup_seed_phrase_workflow(self):
self.open_wallet_settings()
click_obj_by_name(WalletSettingsScreen.BACKUP_SEED_PHRASE_BUTTON.value)
# Check all checkboxes and click next button
obj = wait_and_get_obj(BackupSeedPhrasePopup.HAVE_PEN_CHECKBOX.value)
obj.checked = True
obj = wait_and_get_obj(BackupSeedPhrasePopup.WRITE_DOWN_CHECKBOX.value)
obj.checked = True
obj = wait_and_get_obj(BackupSeedPhrasePopup.STORE_IT_CHECKBOX.value)
obj.checked = True
click_obj_by_name(BackupSeedPhrasePopup.NEXT_BUTTON.value)
# Show seed phrase
click_obj_by_name(BackupSeedPhrasePopup.REVEAL_SEED_PHRASE_BUTTON.value)
# Collect word phrases for the next random confirmation steps
seed_phrase = [wait_by_wildcards(BackupSeedPhrasePopup.SEED_PHRASE_WORD_PLACEHOLDER.value, "%WORD_NO%", str(i + 1)).textEdit.input.edit.text for i in range(12)]
click_obj_by_name(BackupSeedPhrasePopup.NEXT_BUTTON.value)
# Confirm first random word of the seed phrase
firstSeedBaseObj = wait_and_get_obj(BackupSeedPhrasePopup.CONFIRM_FIRST_WORD_PAGE.value)
firstSeedWord = str(seed_phrase[firstSeedBaseObj.wordRandomNumber])
wait_for_object_and_type(BackupSeedPhrasePopup.CONFIRM_FIRST_WORD_INPUT.value, firstSeedWord)
click_obj_by_name(BackupSeedPhrasePopup.NEXT_BUTTON.value)
# Confirm second random word of the seed phrase
secondSeedBaseObj = wait_and_get_obj(BackupSeedPhrasePopup.CONFIRM_SECOND_WORD_PAGE.value)
secondSeedWord = str(seed_phrase[secondSeedBaseObj.wordRandomNumber])
wait_for_object_and_type(BackupSeedPhrasePopup.CONFIRM_SECOND_WORD_INPUT.value, secondSeedWord)
click_obj_by_name(BackupSeedPhrasePopup.NEXT_BUTTON.value)
# Acknowledge and confirm that you won't have access to the seed phrase anymore
obj = wait_and_get_obj(BackupSeedPhrasePopup.CONFIRM_YOU_STORED_CHECKBOX.value)
obj.checked = True
click_obj_by_name(BackupSeedPhrasePopup.CONFIRM_YOU_STORED_BUTTON.value)
def verify_seed_phrase_indicator_not_visible(self):
verify_not_found(WalletSettingsScreen.BACKUP_SEED_PHRASE_BUTTON.value, "Check that backup seed phrase settings button is visible")

View File

@ -238,7 +238,7 @@ class StatusCommunityScreen:
verify_text_matching(CommunitySettingsComponents.COMMUNITY_NAME_TEXT.value, new_community_name)
verify_text_matching(CommunitySettingsComponents.COMMUNITY_DESCRIPTION_TEXT.value, new_community_description)
obj = get_obj(CommunitySettingsComponents.COMMUNITY_LETTER_IDENTICON.value)
expectTrue(obj.color.name == new_community_color, "Community color was not changed correctly")
expect_true(obj.color.name == new_community_color, "Community color was not changed correctly")
def go_back_to_community(self):
click_obj_by_name(CommunitySettingsComponents.BACK_TO_COMMUNITY_BUTTON.value)
@ -263,10 +263,10 @@ class StatusCommunityScreen:
# Search emoji
wait_for_object_and_type(CreateOrEditCommunityChannelPopup.EMOJI_SEARCH_TEXT_INPUT.value, emoji_description)
# Click on the first found emoji button
click_obj_by_wildcards_name(CreateOrEditCommunityChannelPopup.EMOJI_POPUP_EMOJI_PLACEHOLDER.value, "statusEmoji_*")
click_obj(wait_by_wildcards(CreateOrEditCommunityChannelPopup.EMOJI_POPUP_EMOJI_PLACEHOLDER.value, "%NAME%", "*"))
# save changes
click_obj_by_name(CreateOrEditCommunityChannelPopup.COMMUNITY_CHANNEL_SAVE_OR_CREATE_BUTTON.value)
def check_community_channel_emoji(self, emojiStr: str):
obj = wait_and_get_obj(CommunityScreenComponents.CHAT_IDENTIFIER_CHANNEL_ICON.value)
expectTrue(str(obj.icon.emoji).find(emojiStr) >= 0, "Same emoji check")
expect_true(str(obj.icon.emoji).find(emojiStr) >= 0, "Same emoji check")

View File

@ -0,0 +1,15 @@
# encoding: UTF-8
import squish
import object
import names
import test
def debugWaitForObject(objRealName: dict, timeoutMSec: int = 1000):
return squish.waitForObject(objRealName, timeoutMSec)
def type_text(obj, text: str):
squish.type(obj, text)
def find_object(objRealName: dict):
obj = squish.findObject(objRealName)

View File

@ -79,6 +79,7 @@ settings_Wallet_AccountView_EditAccountSaveButton = {"container": statusDesktop_
settings_Wallet_AccountView_EditAccountColorRepeater = {"container": statusDesktop_mainWindow, "type": "Repeater", "objectName": "statusColorRepeater", "visible": True}
settings_Wallet_AccountView_AccountName = {"container": statusDesktop_mainWindow, "type": "StatusBaseText", "objectName": "walletAccountViewAccountName"}
settings_Wallet_AccountView_IconSettings = {"container": statusDesktop_mainWindow, "type": "StatusSmartIdenticon", "objectName": "walletAccountViewAccountImage" , "visible": True}
settings_Wallet_MainView_BackupSeedPhrase = {"container": mainWindow_ScrollView, "objectName": SettingsSubsection.BACKUP_SEED.value, "type": "StatusNavigationListItem", "visible": True}
generatedAccounts_ListView = {"container": statusDesktop_mainWindow, "objectName": "generatedAccounts", "type": "ListView"}
@ -99,3 +100,17 @@ languageView_language_StatusListPicker = {"container": statusDesktop_mainWindow,
languageView_language_StatusPickerButton = {"container": languageView_language_StatusListPicker, "type": "StatusPickerButton", "unnamed": 1}
languageView_language_ListView = {"container": languageView_language_StatusListPicker, "type": "ListView", "unnamed": 1}
languageView_language_StatusInput = {"container": languageView_language_ListView, "type": "StatusInput", "unnamed": 1}
# Backup seed phrase:
backup_seed_phrase_popup_Acknowledgements_havePen_checkbox = {"container": statusDesktop_mainWindow_overlay, "objectName": "Acknowledgements_havePen", "type": "StatusCheckBox", "checkable": True, "visible": True}
backup_seed_phrase_popup_Acknowledgements_writeDown_checkbox = {"container": statusDesktop_mainWindow_overlay, "objectName": "Acknowledgements_writeDown", "type": "StatusCheckBox", "checkable": True, "visible": True}
backup_seed_phrase_popup_Acknowledgements_storeIt_checkbox = {"container": statusDesktop_mainWindow_overlay, "objectName": "Acknowledgements_storeIt", "type": "StatusCheckBox", "checkable": True, "visible": True}
backup_seed_phrase_popup_nextButton = {"container": statusDesktop_mainWindow_overlay, "objectName": "BackupSeedModal_nextButton", "type": "StatusButton", "visible": True, "enabled": True}
backup_seed_phrase_popup_ConfirmSeedPhrasePanel_RevealSeedPhraseButton = {"container": statusDesktop_mainWindow_overlay, "objectName": "ConfirmSeedPhrasePanel_RevealSeedPhraseButton", "type": "StatusButton", "visible": True}
backup_seed_phrase_popup_ConfirmSeedPhrasePanel_StatusSeedPhraseInput_placeholder = {"container": statusDesktop_mainWindow_overlay, "objectName": "ConfirmSeedPhrasePanel_StatusSeedPhraseInput_%WORD_NO%", "type": "StatusSeedPhraseInput", "visible": True}
backup_seed_phrase_popup_BackupSeedStepBase_confirmFirstWord = {"container": statusDesktop_mainWindow_overlay, "objectName": "BackupSeedModal_BackupSeedStepBase_confirmFirstWord", "type": "BackupSeedStepBase", "visible": True}
backup_seed_phrase_popup_BackupSeedStepBase_confirmFirstWord_inputText = {"container": backup_seed_phrase_popup_BackupSeedStepBase_confirmFirstWord, "objectName": "BackupSeedStepBase_inputText", "type": "TextEdit", "visible": True}
backup_seed_phrase_popup_BackupSeedStepBase_confirmSecondWord = {"container": statusDesktop_mainWindow_overlay, "objectName": "BackupSeedModal_BackupSeedStepBase_confirmSecondWord", "type": "BackupSeedStepBase", "visible": True}
backup_seed_phrase_popup_BackupSeedStepBase_confirmSecondWord_inputText = {"container": backup_seed_phrase_popup_BackupSeedStepBase_confirmSecondWord, "objectName": "BackupSeedStepBase_inputText", "type": "TextEdit", "visible": True}
backup_seed_phrase_popup_ConfirmStoringSeedPhrasePanel_storeCheck = {"container": statusDesktop_mainWindow_overlay, "objectName": "ConfirmStoringSeedPhrasePanel_storeCheck", "type": "StatusCheckBox", "checkable": True, "visible": True}
backup_seed_phrase_popup_BackupSeedModal_completeAndDeleteSeedPhraseButton = {"container": statusDesktop_mainWindow_overlay, "objectName": "BackupSeedModal_completeAndDeleteSeedPhraseButton", "type": "StatusButton", "visible": True}

View File

@ -134,3 +134,11 @@ def step(context, native):
_languageScreen.verify_current_language(native)
# TODO: Verify some texts have been changed in the application (not done now bc translations are inconsistent
# and not all expected languages have the same texts translated
@When("the user backs up the wallet seed phrase")
def step(context):
_settingsScreen.check_backup_seed_phrase_workflow()
@Then("the backup seed phrase indicator is not displayed")
def step(context):
_settingsScreen.verify_seed_phrase_indicator_not_visible()

View File

@ -12,3 +12,8 @@ Feature: Status Desktop Settings Menu
Scenario: The user quits the app
When the user clicks on Sign out and Quit
Then the app is closed
Scenario: User can backup seed phrase
When the user activates wallet and opens the wallet settings
And the user backs up the wallet seed phrase
Then the backup seed phrase indicator is not displayed

View File

@ -56,6 +56,7 @@ StatusStackModal {
rightButtons: [ d.skipButton, nextButton, finishButton ]
nextButton: StatusButton {
objectName: "BackupSeedModal_nextButton"
enabled: {
switch (root.currentIndex) {
case 0:
@ -87,6 +88,7 @@ StatusStackModal {
finishButton: StatusButton {
text: qsTr("Complete & Delete My Seed Phrase")
objectName: "BackupSeedModal_completeAndDeleteSeedPhraseButton"
enabled: d.seedStored
onClicked: {
root.privacyStore.removeMnemonic();
@ -112,12 +114,14 @@ StatusStackModal {
},
BackupSeedStepBase {
id: confirmFirstWord
objectName: "BackupSeedModal_BackupSeedStepBase_confirmFirstWord"
titleText: qsTr("Confirm word #%1 of your seed phrase").arg(d.firstRandomNo + 1)
wordRandomNumber: d.firstRandomNo
wordAtRandomNumber: root.privacyStore.getMnemonicWordAtIndex(d.firstRandomNo)
},
BackupSeedStepBase {
id: confirmSecondWord
objectName: "BackupSeedModal_BackupSeedStepBase_confirmSecondWord"
titleText: qsTr("Confirm word #%1 of your seed phrase").arg(d.secondRandomNo + 1)
wordRandomNumber: d.secondRandomNo
wordAtRandomNumber: root.privacyStore.getMnemonicWordAtIndex(d.secondRandomNo)

View File

@ -80,6 +80,7 @@ ColumnLayout {
StatusCheckBox {
id: havePen
objectName: "Acknowledgements_havePen"
spacing: Style.current.padding
text: qsTr("I have a pen and paper")
font.pixelSize: Style.current.primaryTextFontSize
@ -88,6 +89,7 @@ ColumnLayout {
StatusCheckBox {
id: writeDown
objectName: "Acknowledgements_writeDown"
spacing: Style.current.padding
text: qsTr("I am ready to write down my seed phrase")
font.pixelSize: Style.current.primaryTextFontSize
@ -96,6 +98,7 @@ ColumnLayout {
StatusCheckBox {
id: storeIt
objectName: "Acknowledgements_storeIt"
spacing: Style.current.padding
text: qsTr("I know where Ill store it")
font.pixelSize: Style.current.primaryTextFontSize

View File

@ -37,6 +37,7 @@ StatusScrollView {
StatusInput {
id: inputText
input.edit.objectName: "BackupSeedStepBase_inputText"
visible: (wordRandomNumber > -1)
implicitWidth: 448
label: qsTr("Word #%1").arg(wordRandomNumber + 1)

View File

@ -37,6 +37,7 @@ BackupSeedStepBase {
readonly property int spacing: 4
delegate: StatusSeedPhraseInput {
id: seedWordInput
objectName: "ConfirmSeedPhrasePanel_StatusSeedPhraseInput_" + grid.wordIndex[index]
width: (grid.cellWidth - grid.spacing)
height: (grid.cellHeight - grid.spacing)
textEdit.input.edit.enabled: false
@ -61,6 +62,7 @@ BackupSeedStepBase {
}
StatusButton {
objectName: "ConfirmSeedPhrasePanel_RevealSeedPhraseButton"
anchors.centerIn: parent
visible: hideSeed
icon.name: "view"

View File

@ -53,6 +53,7 @@ BackupSeedStepBase {
StatusCheckBox {
id: storeCheck
objectName: "ConfirmStoringSeedPhrasePanel_storeCheck"
spacing: Style.current.padding
font.pixelSize: Style.current.primaryTextFontSize
text: qsTr("I acknowledge that Status will not be able to show me my seed phrase again.")