test(chore/suite_messaging): Added specific `bdd_hooks` for `suite_messaging/tst_ChatFlow`

- Reviewed `suite_messaging/tst_ChatFlow` feature: Cleanup of duplicated steps and separation of action / validation applied.

- Reviewed `suite_messaging/tst_groupChat` feature.

- Added new tag to `Jenkins` file: `relyon-mailserver`.

- Added new `StartupSteps` class to manage init / startup static methods outside bdd steps. It can be used as a util in `hooks` and `steps`.

Closes #7931
This commit is contained in:
Noelia 2022-10-13 18:03:10 +02:00 committed by Noelia
parent 7706a6caea
commit 728aa00c3c
15 changed files with 826 additions and 615 deletions

View File

@ -115,6 +115,9 @@ pipeline {
--tags --tags
~merge ~merge
--tags
~relyon-mailserver
--config --config
addAUT addAUT
nim_status_client nim_status_client

View File

@ -1,19 +1,18 @@
from drivers.SquishDriver import * import drivers.SquishDriver as driver
from drivers.SquishDriverVerification import * import drivers.SquishDriverVerification as verification
def start_application(app_name: str):
driver.start_application(app_name)
def click_on_an_object(objName: str): def click_on_an_object(objName: str):
click_obj_by_name(objName) driver.click_obj_by_name(objName)
def input_text(text: str, objName: str): def input_text(text: str, objName: str):
type(objName, text) driver.type(objName, text)
def object_not_enabled(objName: str): def object_not_enabled(objName: str):
verify_object_enabled(objName, 500, False) verification.verify_object_enabled(objName, 500, False)
def str_to_bool(string: str): def str_to_bool(string: str):
return string.lower() in ["yes", "true", "1", "y", "enabled"] return string.lower() in ["yes", "true", "1", "y", "enabled"]

View File

@ -30,6 +30,9 @@ _MIN_WAIT_OBJ_TIMEOUT = 500
_SEARCH_IMAGES_PATH = "../shared/searchImages/" _SEARCH_IMAGES_PATH = "../shared/searchImages/"
def start_application(app_name: str):
squish.startApplication(app_name)
# Waits for the given object is loaded, visible and enabled. # Waits for the given object is loaded, visible and enabled.
# It returns a tuple: True in case it is found. Otherwise, false. And the object itself. # It returns a tuple: True in case it is found. Otherwise, false. And the object itself.
def is_loaded_visible_and_enabled(objName: str, timeout: int=_MAX_WAIT_OBJ_TIMEOUT): def is_loaded_visible_and_enabled(objName: str, timeout: int=_MAX_WAIT_OBJ_TIMEOUT):

View File

@ -106,6 +106,9 @@ class StatusChatScreen:
verify_screen(ChatComponents.MESSAGE_INPUT.value) verify_screen(ChatComponents.MESSAGE_INPUT.value)
verify_screen(ChatComponents.TOOLBAR_INFO_BUTTON.value) verify_screen(ChatComponents.TOOLBAR_INFO_BUTTON.value)
#####################################
### Screen get states:
#####################################
def chat_loaded(self): def chat_loaded(self):
verify(is_displayed(ChatComponents.LAST_MESSAGE.value), "Checking chat is loaded by looking if last message is displayed.") verify(is_displayed(ChatComponents.LAST_MESSAGE.value), "Checking chat is loaded by looking if last message is displayed.")
@ -113,16 +116,18 @@ class StatusChatScreen:
obj = wait_and_get_obj(ChatComponents.CHAT_LOG.value).itemAtIndex(int(index)) obj = wait_and_get_obj(ChatComponents.CHAT_LOG.value).itemAtIndex(int(index))
return obj return obj
# Screen actions region: #####################################
def type_message_in_chat_input(self, message: str): ### Screen actions region:
#####################################
def type_message(self, message: str):
type(ChatComponents.MESSAGE_INPUT.value, message) type(ChatComponents.MESSAGE_INPUT.value, message)
def press_enter_in_chat_input(self): def press_enter(self):
press_enter(ChatComponents.MESSAGE_INPUT.value) press_enter(ChatComponents.MESSAGE_INPUT.value)
def send_message(self, message: str): def send_message(self, message: str):
self.type_message_in_chat_input(message) self.type_message(message)
self.press_enter_in_chat_input() self.press_enter()
def clear_history(self): def clear_history(self):
click_obj_by_name(ChatComponents.MORE_OPTIONS_BUTTON.value) click_obj_by_name(ChatComponents.MORE_OPTIONS_BUTTON.value)
@ -167,11 +172,6 @@ class StatusChatScreen:
workflow.cropImage(groupChatUrl) workflow.cropImage(groupChatUrl)
click_obj_by_name(GroupChatEditPopup.GROUP_CHAT_CROPPER_ACCEPT_BUTTON.value) click_obj_by_name(GroupChatEditPopup.GROUP_CHAT_CROPPER_ACCEPT_BUTTON.value)
# Verifications region:
def verify_last_message_is_not_loaded(self):
[loaded, _] = is_loaded_visible_and_enabled(ChatComponents.LAST_MESSAGE_TEXT.value)
verify_false(loaded, "Success: No message was found")
def send_gif(self): def send_gif(self):
click_obj_by_name(ChatComponents.GIF_POPUP_BUTTON.value) click_obj_by_name(ChatComponents.GIF_POPUP_BUTTON.value)
click_obj_by_name(ChatComponents.ENABLE_GIF_BUTTON.value) click_obj_by_name(ChatComponents.ENABLE_GIF_BUTTON.value)
@ -181,7 +181,139 @@ class StatusChatScreen:
def select_the_emoji_in_suggestion_list(self): def select_the_emoji_in_suggestion_list(self):
click_obj_by_name(Emoji.EMOJI_SUGGESTIONS_FIRST_ELEMENT.value) click_obj_by_name(Emoji.EMOJI_SUGGESTIONS_FIRST_ELEMENT.value)
# Verifications region: def reply_to_message_at_index(self, index: int, message: str):
message_object_to_reply_to = self.get_message_at_index(index)
verify(not is_null(message_object_to_reply_to), "Message to reply to is loaded")
move_mouse_over_object(message_object_to_reply_to)
click_obj_by_name(ChatComponents.REPLY_TO_MESSAGE_BUTTON.value)
self.send_message(message)
def edit_message_at_index(self, index: int, message: str):
message_object_to_edit = get_obj(ChatComponents.CHAT_LOG.value).itemAtIndex(int(index))
hover_obj(message_object_to_edit)
click_obj_by_name(ChatComponents.EDIT_MESSAGE_BUTTON.value)
wait_for_object_and_type(ChatComponents.EDIT_MESSAGE_TEXTAREA.value, "<Ctrl+a>")
type(ChatComponents.EDIT_MESSAGE_TEXTAREA.value, message)
press_enter(ChatComponents.EDIT_MESSAGE_TEXTAREA.value)
def switch_to_chat(self, chatName: str):
chat_lists = get_obj(ChatComponents.CHAT_LIST.value)
verify(chat_lists.count > 0, "At least one chat exists")
for i in range(chat_lists.count):
chat = chat_lists.itemAt(i)
chat_list_items = getChildrenWithObjectName(chat, "chatItem")
verify(len(chat_list_items) > 0, "StatusChatListItem exists")
if str(chat_list_items[0].name) == chatName:
click_obj(chat)
return
verify(False, "Chat switched")
# TODO: Find ADMIN
def find_member_in_panel(self, member: str):
found = False
[is_loaded, membersList] = is_loaded_visible_and_enabled(ChatComponents.MEMBERS_LISTVIEW.value)
if is_loaded:
for index in range(membersList.count):
user = membersList.itemAtIndex(index)
if(user.userName == member):
found = True
break
return found
def delete_message_at_index(self, index: int):
message_object_to_delete = self.get_message_at_index(index)
move_mouse_over_object(message_object_to_delete)
click_obj_by_name(ChatComponents.DELETE_MESSAGE_BUTTON.value)
click_obj_by_name(ChatComponents.CONFIRM_DELETE_MESSAGE_BUTTON.value)
def cannot_delete_last_message(self):
[loaded, last_message_obj] = is_loaded_visible_and_enabled(ChatComponents.LAST_MESSAGE.value)
if not loaded:
verify_failure("No message found")
return
hover_obj(last_message_obj)
object_not_enabled(ChatComponents.DELETE_MESSAGE_BUTTON.value)
def send_message_with_mention(self, displayName: str, message: str):
self.do_mention(displayName)
self.send_message(message)
def cannot_do_mention(self, displayName: str):
self.type_message(_MENTION_SYMBOL + displayName)
displayed = is_displayed(ChatComponents.SUGGESTIONS_BOX.value)
self.press_enter()
verify(displayed == False , "Checking suggestion box is not displayed when trying to mention a non existing user.")
def do_mention(self, displayName: str):
self.type_message(_MENTION_SYMBOL + displayName)
displayed = is_displayed(ChatComponents.SUGGESTIONS_BOX.value)
verify(displayed, "Checking suggestion box displayed when trying to do a mention")
[loaded, suggestions_list] = is_loaded_visible_and_enabled(ChatComponents.SUGGESTIONS_LIST.value)
verify(suggestions_list.count > 0, "Checking if suggestion list is greater than 0")
found = False
if loaded:
for index in range(suggestions_list.count):
user_mention = suggestions_list.itemAtIndex(index)
if user_mention.objectName == displayName:
found = True
click_obj(user_mention)
break
verify(found, "Checking if the following display name is in the mention's list: " + displayName)
def install_sticker_pack(self, pack_index: str):
click_obj_by_name(ChatComponents.CHAT_INPUT_STICKER_BUTTON.value)
click_obj_by_name(ChatStickerPopup.STICKERS_POPUP_GET_STICKERS_BUTTON.value)
# Wait for grid view to be loaded
loaded, grid_view = is_loaded_visible_and_enabled(ChatStickerPopup.STICKERS_POPUP_MARKET_GRID_VIEW.value)
if (not loaded):
verify_failure("Sticker market grid view is not loaded")
# Wait for the items in the GridView to be loaded
verify(is_displayed(ChatStickerPopup.STICKERS_POPUP_MARKET_GRID_VIEW_DELEGATE_ITEM_1.value), "Sticker item 0 is not displayed")
scroll_list_view_at_index(grid_view, int(pack_index))
sticker_pack = grid_view.itemAtIndex(int(pack_index))
click_obj(sticker_pack)
# Install and close
click_obj_by_name(ChatStickerPopup.STICKERS_POPUP_MARKET_INSTALL_BUTTON.value)
click_obj_by_name(ChatStickerPopup.MODAL_CLOSE_BUTTON.value)
verify(sticker_pack.installed == True, "The sticker pack at position " + str(pack_index) + " was not installed")
#Close sticker popup
click_obj_by_name(ChatComponents.CHAT_INPUT_STICKER_BUTTON.value)
def send_sticker(self, sticker_index: int):
click_obj_by_name(ChatComponents.CHAT_INPUT_STICKER_BUTTON.value)
loaded, sticker_list_grid = is_loaded_visible_and_enabled(ChatStickerPopup.STICKER_LIST_GRID.value)
if (not loaded):
verify_failure("Sticker list grid view is not loaded")
sticker = sticker_list_grid.itemAtIndex(int(sticker_index))
click_obj(sticker)
def send_emoji(self, emoji_short_name: str, message: str):
if (message != ""):
self.type_message(message)
click_obj_by_name(ChatComponents.CHAT_INPUT_EMOJI_BUTTON.value)
emojiAttr = copy.deepcopy(getattr(names, ChatComponents.EMOJI_POPUP_EMOJI_PLACEHOLDER.value))
emojiAttr["objectName"] = emojiAttr["objectName"].replace("%NAME%", emoji_short_name)
click_obj_by_attr(emojiAttr)
self.press_enter()
#####################################
### Verifications region:
#####################################
def verify_last_message_is_not_loaded(self):
[loaded, _] = is_loaded_visible_and_enabled(ChatComponents.LAST_MESSAGE_TEXT.value)
verify_false(loaded, "Success: No message was found")
def verify_last_message_sent(self, message: str): def verify_last_message_sent(self, message: str):
# Get the message text # Get the message text
# We don't search for StatusTextMessage_chatText directly, because there're 2 instances of it in a reply message # We don't search for StatusTextMessage_chatText directly, because there're 2 instances of it in a reply message
@ -266,127 +398,10 @@ class StatusChatScreen:
chat_createChat_text_obj = self.get_message_at_index(ChatMessagesHistory.CHAT_CREATED_TEXT.value) chat_createChat_text_obj = self.get_message_at_index(ChatMessagesHistory.CHAT_CREATED_TEXT.value)
verify_text_contains(str(chat_createChat_text_obj.messageText), createdTxt) verify_text_contains(str(chat_createChat_text_obj.messageText), createdTxt)
def reply_to_message_at_index(self, index: int, message: str): def verify_last_message_is_sticker(self):
message_object_to_reply_to = self.get_message_at_index(index)
verify(not is_null(message_object_to_reply_to), "Message to reply to is loaded")
move_mouse_over_object(message_object_to_reply_to)
click_obj_by_name(ChatComponents.REPLY_TO_MESSAGE_BUTTON.value)
self.send_message(message)
def edit_message_at_index(self, index: int, message: str):
message_object_to_edit = get_obj(ChatComponents.CHAT_LOG.value).itemAtIndex(int(index))
hover_obj(message_object_to_edit)
click_obj_by_name(ChatComponents.EDIT_MESSAGE_BUTTON.value)
wait_for_object_and_type(ChatComponents.EDIT_MESSAGE_TEXTAREA.value, "<Ctrl+a>")
type(ChatComponents.EDIT_MESSAGE_TEXTAREA.value, message)
press_enter(ChatComponents.EDIT_MESSAGE_TEXTAREA.value)
# TODO: Find ADMIN
def find_member_in_panel(self, member: str):
found = False
[is_loaded, membersList] = is_loaded_visible_and_enabled(ChatComponents.MEMBERS_LISTVIEW.value)
if is_loaded:
for index in range(membersList.count):
user = membersList.itemAtIndex(index)
if(user.userName == member):
found = True
break
return found
def delete_message_at_index(self, index: int):
message_object_to_delete = self.get_message_at_index(index)
move_mouse_over_object(message_object_to_delete)
click_obj_by_name(ChatComponents.DELETE_MESSAGE_BUTTON.value)
click_obj_by_name(ChatComponents.CONFIRM_DELETE_MESSAGE_BUTTON.value)
def cannot_delete_last_message(self):
[loaded, last_message_obj] = is_loaded_visible_and_enabled(ChatComponents.LAST_MESSAGE.value)
if not loaded:
verify_failure("No message found")
return
hover_obj(last_message_obj)
object_not_enabled(ChatComponents.DELETE_MESSAGE_BUTTON.value)
def send_message_with_mention(self, displayName: str, message: str):
self.do_mention(displayName)
self.send_message(message)
def cannot_do_mention(self, displayName: str):
self.chat_loaded()
self.type_message_in_chat_input(_MENTION_SYMBOL + displayName)
displayed = is_displayed(ChatComponents.SUGGESTIONS_BOX.value)
verify(displayed == False , "Checking suggestion box is not displayed when trying to mention a non existing user.")
def do_mention(self, displayName: str):
self.chat_loaded()
self.type_message_in_chat_input(_MENTION_SYMBOL + displayName)
displayed = is_displayed(ChatComponents.SUGGESTIONS_BOX.value)
verify(displayed, "Checking suggestion box displayed when trying to do a mention")
[loaded, suggestions_list] = is_loaded_visible_and_enabled(ChatComponents.SUGGESTIONS_LIST.value)
verify(suggestions_list.count > 0, "Checking if suggestion list is greater than 0")
found = False
if loaded:
for index in range(suggestions_list.count):
user_mention = suggestions_list.itemAtIndex(index)
if user_mention.objectName == displayName:
found = True
click_obj(user_mention)
break
verify(found, "Checking if the following display name is in the mention's list: " + displayName)
def install_sticker_pack(self, pack_index: str):
click_obj_by_name(ChatComponents.CHAT_INPUT_STICKER_BUTTON.value)
click_obj_by_name(ChatStickerPopup.STICKERS_POPUP_GET_STICKERS_BUTTON.value)
# Wait for grid view to be loaded
loaded, grid_view = is_loaded_visible_and_enabled(ChatStickerPopup.STICKERS_POPUP_MARKET_GRID_VIEW.value)
if (not loaded):
verify_failure("Sticker market grid view is not loaded")
# Wait for the items in the GridView to be loaded
verify(is_displayed(ChatStickerPopup.STICKERS_POPUP_MARKET_GRID_VIEW_DELEGATE_ITEM_1.value), "Sticker item 0 is not displayed")
scroll_list_view_at_index(grid_view, int(pack_index))
sticker_pack = grid_view.itemAtIndex(int(pack_index))
click_obj(sticker_pack)
# Install and close
click_obj_by_name(ChatStickerPopup.STICKERS_POPUP_MARKET_INSTALL_BUTTON.value)
click_obj_by_name(ChatStickerPopup.MODAL_CLOSE_BUTTON.value)
verify(sticker_pack.installed == True, "The sticker pack at position " + str(pack_index) + " was not installed")
#Close sticker popup
click_obj_by_name(ChatComponents.CHAT_INPUT_STICKER_BUTTON.value)
def send_sticker(self, sticker_index: int):
click_obj_by_name(ChatComponents.CHAT_INPUT_STICKER_BUTTON.value)
loaded, sticker_list_grid = is_loaded_visible_and_enabled(ChatStickerPopup.STICKER_LIST_GRID.value)
if (not loaded):
verify_failure("Sticker list grid view is not loaded")
sticker = sticker_list_grid.itemAtIndex(int(sticker_index))
click_obj(sticker)
last_message_obj = get_obj(ChatComponents.CHAT_LOG.value).itemAtIndex(0) last_message_obj = get_obj(ChatComponents.CHAT_LOG.value).itemAtIndex(0)
verify_values_equal(str(last_message_obj.messageContentType), str(MessageContentType.STICKER.value), "The last message is not a sticker") verify_values_equal(str(last_message_obj.messageContentType), str(MessageContentType.STICKER.value), "The last message is not a sticker")
def send_emoji(self, emoji_short_name: str, message: str):
if (message != ""):
self.type_message_in_chat_input(message)
click_obj_by_name(ChatComponents.CHAT_INPUT_EMOJI_BUTTON.value)
emojiAttr = copy.deepcopy(getattr(names, ChatComponents.EMOJI_POPUP_EMOJI_PLACEHOLDER.value))
emojiAttr["objectName"] = emojiAttr["objectName"].replace("%NAME%", emoji_short_name)
click_obj_by_attr(emojiAttr)
self.press_enter_in_chat_input()
def verify_chat_order(self, index: int, chatName: str): def verify_chat_order(self, index: int, chatName: str):
chat_lists = get_obj(ChatComponents.CHAT_LIST.value) chat_lists = get_obj(ChatComponents.CHAT_LIST.value)
chat = chat_lists.itemAt(index) chat = chat_lists.itemAt(index)
@ -395,18 +410,6 @@ class StatusChatScreen:
verify(len(chat_list_items) > 0, "StatusChatListItem exists") verify(len(chat_list_items) > 0, "StatusChatListItem exists")
verify(str(chat_list_items[0].name) == chatName, "Chat in order") verify(str(chat_list_items[0].name) == chatName, "Chat in order")
def switch_to_chat(self, chatName: str):
chat_lists = get_obj(ChatComponents.CHAT_LIST.value)
verify(chat_lists.count > 0, "At least one chat exists")
for i in range(chat_lists.count):
chat = chat_lists.itemAt(i)
chat_list_items = getChildrenWithObjectName(chat, "chatItem")
verify(len(chat_list_items) > 0, "StatusChatListItem exists")
if str(chat_list_items[0].name) == chatName:
click_obj(chat)
return
verify(False, "Chat switched")
def _verify_image_unfurled_status_for_component(self, objectName: str, image_link: str, unfurled: bool): def _verify_image_unfurled_status_for_component(self, objectName: str, image_link: str, unfurled: bool):
if not unfurled: if not unfurled:
verify_false(is_loaded_visible_and_enabled(objectName, 10)[0], "Image link preview component is not loaded") verify_false(is_loaded_visible_and_enabled(objectName, 10)[0], "Image link preview component is not loaded")
@ -420,6 +423,3 @@ class StatusChatScreen:
def verify_link_image_unfurled_status(self, image_link: str, unfurled: bool): def verify_link_image_unfurled_status(self, image_link: str, unfurled: bool):
self._verify_image_unfurled_status_for_component(ChatComponents.LINK_PREVIEW_UNFURLED_LINK_IMAGE.value, image_link, unfurled) self._verify_image_unfurled_status_for_component(ChatComponents.LINK_PREVIEW_UNFURLED_LINK_IMAGE.value, image_link, unfurled)
def open_settings_from_message(self):
click_obj_by_name(ChatComponents.LINK_PREVIEW_OPEN_SETTINGS.value)

View File

@ -4,44 +4,17 @@
sys.path.append(os.path.join(os.path.dirname(__file__), "../../../testSuites/global_shared/")) sys.path.append(os.path.join(os.path.dirname(__file__), "../../../testSuites/global_shared/"))
sys.path.append(os.path.join(os.path.dirname(__file__), "../../../src/")) sys.path.append(os.path.join(os.path.dirname(__file__), "../../../src/"))
from utils.FileManager import * from steps.startupSteps import *
_status_desktop_app_name = "nim_status_client"
_status_data_folder_path = "../../../../../Status/data"
_status_qt_path = "../../../../../Status/qt"
_app_closure_timeout = 2 #[seconds]
@OnScenarioStart @OnScenarioStart
def hook(context): def hook(context):
erase_directory(_status_qt_path) context_init(context)
context.userData = {}
context.userData["aut_name"] = _status_desktop_app_name
context.userData["status_data_folder_path"] = _status_data_folder_path
context.userData["fixtures_root"] = os.path.join(os.path.dirname(__file__), "../../../fixtures/")
context.userData["search_images"] = os.path.join(os.path.dirname(__file__), "../shared/searchImages/")
context.userData["scenario_name"] = context._data["title"]
base_path = os.path.join(os.path.dirname(__file__))
split_path = base_path.split("/")
# Remove the last three parts of the path to go back to the fixtures
del split_path[len(split_path) - 1]
del split_path[len(split_path) - 1]
del split_path[len(split_path) - 1]
joined_path = ""
for path_part in split_path:
joined_path += path_part + "/"
context.userData["fixtures_root"] = os.path.join(joined_path, "fixtures/")
@OnScenarioEnd @OnScenarioEnd
def hook(context): def hook(context):
currentApplicationContext().detach() currentApplicationContext().detach()
snooze(_app_closure_timeout) snooze(_app_closure_timeout)
@OnStepEnd @OnStepEnd
def hook(context): def hook(context):
context.userData["step_name"] = context._data["text"] context.userData["step_name"] = context._data["text"]

View File

@ -7,10 +7,29 @@ _statusMain = StatusMainScreen()
_settingsScreen = SettingsScreen() _settingsScreen = SettingsScreen()
_languageScreen = StatusLanguageScreen() _languageScreen = StatusLanguageScreen()
#########################
### PRECONDITIONS region:
#########################
@Given("the user opens app settings screen")
def step(context: any):
the_user_opens_app_settings_screen()
@Given("the user opens the messaging settings")
def step(context: any):
the_user_opens_the_messaging_settings()
@Given("tenor GIFs preview is enabled")
def step(context: any):
_settingsScreen.check_tenor_gif_preview_is_enabled()
#########################
### ACTIONS region:
#########################
@When("the user opens app settings screen") @When("the user opens app settings screen")
def step(context: any): def step(context: any):
_statusMain.open_settings() the_user_opens_app_settings_screen()
@When("the user opens the wallet settings") @When("the user opens the wallet settings")
def step(context: any): def step(context: any):
@ -18,7 +37,7 @@ def step(context: any):
@When("the user opens the messaging settings") @When("the user opens the messaging settings")
def step(context: any): def step(context: any):
_settingsScreen.open_messaging_settings() the_user_opens_the_messaging_settings()
@When("the user activates link preview") @When("the user activates link preview")
def step(context: any): def step(context: any):
@ -28,10 +47,6 @@ def step(context: any):
def step(context: any): def step(context: any):
_settingsScreen.activate_image_unfurling() _settingsScreen.activate_image_unfurling()
@Then("tenor GIFs preview is enabled")
def step(context: any):
_settingsScreen.check_tenor_gif_preview_is_enabled()
@When("the user activates wallet and opens the wallet settings") @When("the user activates wallet and opens the wallet settings")
def step(context: any): def step(context: any):
_settingsScreen.activate_open_wallet_settings() _settingsScreen.activate_open_wallet_settings()
@ -80,27 +95,11 @@ def step(context, native):
def step(context, native): def step(context, native):
_languageScreen.search_language(native) _languageScreen.search_language(native)
@Then("the address |any| is displayed in the wallet")
def step(context: any, address: str):
_settingsScreen.verify_address(address)
@Then("the account |any| is not in the list of accounts")
def step(context: any, account_name):
_settingsScreen.verify_no_account(account_name)
@Then("the new account with name |any| and color |any| is updated")
def step(context, new_name: str, new_color: str):
_settingsScreen.verify_editedAccount(new_name, new_color)
@When("the user clicks on Sign out and Quit") @When("the user clicks on Sign out and Quit")
def step(context: any): def step(context: any):
ctx = currentApplicationContext() ctx = currentApplicationContext()
_settingsScreen.sign_out_and_quit_the_app(ctx.pid) _settingsScreen.sign_out_and_quit_the_app(ctx.pid)
@Then("the app is closed")
def step(context: any):
_settingsScreen.verify_the_app_is_closed()
@When("the user opens the communities settings") @When("the user opens the communities settings")
def step(context: any): def step(context: any):
_settingsScreen.open_communities_section() _settingsScreen.open_communities_section()
@ -117,14 +116,66 @@ def step(context: any):
def step(context, display_name): def step(context, display_name):
_settingsScreen.set_display_name(display_name) _settingsScreen.set_display_name(display_name)
@Then("the user's display name should be \"|any|\"") @When("the user backs up the wallet seed phrase")
def step(context, display_name): def step(context):
_settingsScreen.verify_display_name(display_name) _settingsScreen.check_backup_seed_phrase_workflow()
@When("the user sets display links to twitter: \"|any|\", personal site: \"|any|\", \"|any|\": \"|any|\"")
def step(context, twitter, personal_site, custom_link_name, custom_link):
_settingsScreen.set_social_links(twitter, personal_site, custom_link_name, custom_link)
@When("the user sets bio to \"|any|\"") @When("the user sets bio to \"|any|\"")
def step(context, bio): def step(context, bio):
_settingsScreen.set_bio(bio) _settingsScreen.set_bio(bio)
@When("the users switches state to offline")
def step(context: any):
_statusMain.set_user_state_offline()
@When("the users switches state to online")
def step(context: any):
_statusMain.set_user_state_online()
@When("the users switches state to automatic")
def step(context: any):
_statusMain.set_user_state_to_automatic()
@When("the user opens own profile popup")
def step(context: any):
_statusMain.open_own_profile_popup()
@When("in profile popup the user sets display name to \"|any|\"")
def step(context, display_name):
_statusMain.set_profile_popup_display_name(display_name)
@When("the user changes the password from |any| to |any|")
def step(context: any, oldPassword: str, newPassword: str):
_settingsScreen.change_user_password(oldPassword, newPassword)
#########################
### VERIFICATIONS region:
#########################
@Then("the address |any| is displayed in the wallet")
def step(context: any, address: str):
_settingsScreen.verify_address(address)
@Then("the account |any| is not in the list of accounts")
def step(context: any, account_name):
_settingsScreen.verify_no_account(account_name)
@Then("the new account with name |any| and color |any| is updated")
def step(context, new_name: str, new_color: str):
_settingsScreen.verify_editedAccount(new_name, new_color)
@Then("the app is closed")
def step(context: any):
_settingsScreen.verify_the_app_is_closed()
@Then("the user's display name should be \"|any|\"")
def step(context, display_name):
_settingsScreen.verify_display_name(display_name)
@Then("the user's bio should be empty") @Then("the user's bio should be empty")
def step(context): def step(context):
_settingsScreen.verify_bio("") _settingsScreen.verify_bio("")
@ -133,10 +184,6 @@ def step(context):
def step(context, bio): def step(context, bio):
_settingsScreen.verify_bio(bio) _settingsScreen.verify_bio(bio)
@When("the user sets display links to twitter: \"|any|\", personal site: \"|any|\", \"|any|\": \"|any|\"")
def step(context, twitter, personal_site, custom_link_name, custom_link):
_settingsScreen.set_social_links(twitter, personal_site, custom_link_name, custom_link)
@Then("the user's social links should be empty") @Then("the user's social links should be empty")
def step(context): def step(context):
_settingsScreen.verify_social_links("", "", "", "") _settingsScreen.verify_social_links("", "", "", "")
@ -151,26 +198,10 @@ def step(context, native):
# TODO: Verify some texts have been changed in the application (not done now bc translations are inconsistent # 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 # 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") @Then("the backup seed phrase indicator is not displayed")
def step(context): def step(context):
_settingsScreen.verify_seed_phrase_indicator_not_visible() _settingsScreen.verify_seed_phrase_indicator_not_visible()
@When("the users switches state to offline")
def step(context: any):
_statusMain.set_user_state_offline()
@When("the users switches state to online")
def step(context: any):
_statusMain.set_user_state_online()
@When("the users switches state to automatic")
def step(context: any):
_statusMain.set_user_state_to_automatic()
@Then("the user appears offline") @Then("the user appears offline")
def step(context: any): def step(context: any):
_statusMain.user_is_offline() _statusMain.user_is_offline()
@ -183,18 +214,16 @@ def step(context: any):
def step(context: any): def step(context: any):
_statusMain.user_is_set_to_automatic() _statusMain.user_is_set_to_automatic()
@When("the user opens own profile popup")
def step(context: any):
_statusMain.open_own_profile_popup()
@Then("in profile popup the user's display name should be \"|any|\"") @Then("in profile popup the user's display name should be \"|any|\"")
def step(context, display_name): def step(context, display_name):
_statusMain.verify_profile_popup_display_name(display_name) _statusMain.verify_profile_popup_display_name(display_name)
@When("in profile popup the user sets display name to \"|any|\"") ###########################################################################
def step(context, display_name): ### COMMON methods used in different steps given/when/then region:
_statusMain.set_profile_popup_display_name(display_name) ###########################################################################
@When("the user changes the password from |any| to |any|") def the_user_opens_app_settings_screen():
def step(context: any, oldPassword: str, newPassword: str): _statusMain.open_settings()
_settingsScreen.change_user_password(oldPassword, newPassword)
def the_user_opens_the_messaging_settings():
_settingsScreen.open_messaging_settings()

View File

@ -0,0 +1,81 @@
"""It defines starting-up or driving-the-app-into-an-idle-state static methods outside bdd context that can be reused in different `hooks` as well as in specific bdd steps files."""
from utils.FileManager import *
from common.Common import *
from screens.StatusWelcomeScreen import StatusWelcomeScreen
from screens.StatusMainScreen import StatusMainScreen
from screens.StatusChatScreen import StatusChatScreen
# Project settings properties:
_status_desktop_app_name = "nim_status_client"
_status_data_folder_path = "../../../../../Status/data"
_status_fixtures_folder_path = "../../../fixtures/"
_status_shared_images_path = "../shared/searchImages/"
_status_qt_path = "../../../../../Status/qt"
_app_closure_timeout = 2 #[seconds]
# Test context properties names:
_aut_name = "aut_name"
_status_data_folder = "status_data_folder_path"
_fixtures_root = "fixtures_root"
_search_images = "search_images"
_scenario_name = "scenario_name"
# Test static objects creation:
_welcome_screen = StatusWelcomeScreen()
_main_screen = StatusMainScreen()
_chat_screen = StatusChatScreen()
def context_init(context):
erase_directory(_status_qt_path)
context.userData = {}
context.userData[_aut_name] = _status_desktop_app_name
context.userData[_status_data_folder] = _status_data_folder_path
context.userData[_fixtures_root] = os.path.join(os.path.dirname(__file__), _status_fixtures_folder_path)
context.userData[_search_images] = os.path.join(os.path.dirname(__file__), _status_shared_images_path)
context.userData[_scenario_name] = context._data["title"]
base_path = os.path.join(os.path.dirname(__file__))
split_path = base_path.split("/")
# Remove the last three parts of the path to go back to the fixtures
del split_path[len(split_path) - 1]
del split_path[len(split_path) - 1]
del split_path[len(split_path) - 1]
joined_path = ""
for path_part in split_path:
joined_path += path_part + "/"
context.userData[_fixtures_root] = os.path.join(joined_path, "fixtures/")
def given_a_first_time_user_lands_on_and_generates_new_key(context):
erase_directory(context.userData[_status_data_folder])
start_application(context.userData[_aut_name])
_welcome_screen.agree_terms_conditions_and_generate_new_key()
def given_a_first_time_user_lands_on_and_navigates_to_import_seed_phrase(context):
erase_directory(context.userData[_status_data_folder])
start_application(context.userData[_aut_name])
_welcome_screen.agree_terms_conditions_and_navigate_to_import_seed_phrase()
def when_the_user_signs_up(user, password):
_welcome_screen = StatusWelcomeScreen()
_welcome_screen.input_username_and_password_and_finalize_sign_up(user, password)
def when_the_user_lands_on_the_signed_in_app():
_main_screen.is_ready()
def signs_up_process_steps(context, user, password):
given_a_first_time_user_lands_on_and_generates_new_key(context)
when_the_user_signs_up(user, password)
when_the_user_lands_on_the_signed_in_app()
def when_the_user_joins_chat_room(_chat_room):
_main_screen.join_chat_room(_chat_room)
_chat_screen.verify_chat_title(_chat_room)
def when_the_user_opens_the_chat_section():
_main_screen.open_chat_section()

View File

@ -16,41 +16,60 @@
from common.Common import * from common.Common import *
import time import time
from steps.startupSteps import *
from screens.StatusMainScreen import StatusMainScreen from screens.StatusMainScreen import StatusMainScreen
from screens.StatusChatScreen import StatusChatScreen from screens.StatusChatScreen import StatusChatScreen
_statusMain = StatusMainScreen() _statusMain = StatusMainScreen()
_statusChat = StatusChatScreen() _statusChat = StatusChatScreen()
#########################
### PRECONDITIONS region:
#########################
@Given("the user starts the application with a specific data folder |any|") @Given("the user starts the application with a specific data folder |any|")
def step(context, data_folder_path): def step(context, data_folder_path):
waitFor(lambda: currentApplicationContext().detach(), 500)
time.sleep(5)
clear_directory(context.userData["status_data_folder_path"]) clear_directory(context.userData["status_data_folder_path"])
copy_directory(data_folder_path, context.userData["status_data_folder_path"]) copy_directory(data_folder_path, context.userData["status_data_folder_path"])
startApplication(context.userData["aut_name"]) startApplication(context.userData["aut_name"])
@Given("the user restarts the app")
def step(context):
the_user_restarts_the_app(context)
#########################
### ACTIONS region:
#########################
@When("the user restarts the app") @When("the user restarts the app")
def step(context): def step(context):
waitFor(lambda: currentApplicationContext().detach(), 500) the_user_restarts_the_app(context)
time.sleep(5)
startApplication(context.userData["aut_name"])
@When("user inputs the following |any| with ui-component |any|") @When("user inputs the following |any| with ui-component |any|")
def step(context, text, obj): def step(context, text, obj):
input_text(text, obj) input_text(text, obj)
@When("user clicks on the following ui-component |any|") @When("user clicks on the following ui-component |any|")
def step(context, obj): def step(context, obj):
click_on_an_object(obj) click_on_an_object(obj)
@When("user joins chat room |any|") @When("the user joins chat room |any|")
def step(context, room): def step(context, room):
_statusMain.join_chat_room(room) when_the_user_joins_chat_room(room)
_statusChat.verify_chat_title(room)
#########################
### VERIFICATIONS region:
#########################
@Then("the following ui-component |any| is not enabled") @Then("the following ui-component |any| is not enabled")
def step(context, obj): def step(context, obj):
object_not_enabled(obj) object_not_enabled(obj)
###########################################################################
### COMMON methods used in different steps given/when/then region:
###########################################################################
def the_user_restarts_the_app(context: any):
waitFor(lambda: currentApplicationContext().detach(), 500)
time.sleep(5)
startApplication(context.userData["aut_name"])

View File

@ -1,121 +1,221 @@
from random import randint from random import randint
from drivers.SquishDriver import * from steps.startupSteps import *
from screens.StatusMainScreen import StatusMainScreen from screens.StatusMainScreen import StatusMainScreen
from screens.StatusChatScreen import StatusChatScreen from screens.StatusChatScreen import StatusChatScreen
from screens.StatusCreateChatScreen import StatusCreateChatScreen from screens.StatusCreateChatScreen import StatusCreateChatScreen
# Screen's creation:
_statusMain = StatusMainScreen() _statusMain = StatusMainScreen()
_statusChat = StatusChatScreen() _statusChat = StatusChatScreen()
_statusCreateChatView = StatusCreateChatScreen() _statusCreateChatView = StatusCreateChatScreen()
@When("the user opens the chat section") #########################
def step(context): ### PRECONDITIONS region:
_statusMain.open_chat_section() #########################
@When("the user creates a group chat adding users") @Given("the user sends a chat message |any|")
def step(context): def step(context, message):
_statusMain.open_start_chat_view() the_user_sends_a_chat_message(message)
_statusCreateChatView.create_chat(context.table)
@When("the user clicks on |any| chat") @Given("the image |any| is not unfurled in the chat")
def step(context: any, image_link: str):
_statusChat.verify_image_unfurled_status(image_link, False)
@Given("the user types |any|")
def step(context, message):
_statusChat.type_message(message)
@Given("the user selects the emoji in the suggestion's list")
def step(contenxt):
_statusChat.select_the_emoji_in_suggestion_list()
@Given("the user installs the sticker pack at position |any|")
def step(context, pack_index):
_statusChat.install_sticker_pack(pack_index)
@Given("the user creates a group chat adding users")
def step(context):
the_user_creates_a_group_chat_adding_users(context)
@Given("the group chat is created")
def step(context):
the_group_chat_is_created()
@Given("the user clicks on |any| chat")
def step(context, chatName): def step(context, chatName):
_statusMain.open_chat(chatName) _statusMain.open_chat(chatName)
@When("the user inputs a mention to |any| with message |any|") @Given("the user opens the edit group chat popup")
def step(context,displayName,message): def step(context):
_statusChat.send_message_with_mention(displayName, message) _statusChat.open_group_chat_edit_popup()
@Given("the user changes the group name to |any|")
def step(context, groupName):
_statusChat.group_chat_edit_name(groupName)
@Given("the user changes the group color to |any|")
def step(context, groupColor):
_statusChat.group_chat_edit_color(groupColor)
@Given("the user changes the group image")
def step(context):
_statusChat.group_chat_edit_image(context.userData["fixtures_root"])
@Given("the group chat history contains \"|any|\" message")
def step(context, createdTxt):
_statusChat.verify_chat_created_message_is_displayed_in_history(createdTxt)
@Given("the group chat contains the following members")
def step(context):
_statusChat.verify_members_added(context.table)
#########################
### ACTIONS region:
#########################
@When("the user opens the chat section")
def step(context):
when_the_user_opens_the_chat_section()
@When("the user sends a chat message |any|")
def step(context, message):
the_user_sends_a_chat_message(message)
@When("the user replies to the message at index |any| with |any|")
def step(context, message_index, message):
_statusChat.reply_to_message_at_index(message_index, message)
@When("the user edits the message at index |any| and changes it to |any|" )
def step(context, message_index, message):
_statusChat.edit_message_at_index(message_index, message)
@When("the user marks the channel |any| as read")
def step(context, channel):
_statusMain.mark_as_read(channel)
@When("the user deletes the message at index |any|")
def step(context, message_index):
_statusChat.delete_message_at_index(message_index)
time.sleep(1)
@When("the user clears chat history") @When("the user clears chat history")
def step(context): def step(context):
_statusChat.clear_history() _statusChat.clear_history()
@When("the user opens the edit group chat popup") @When("the user sends a GIF message")
def step(context): def step(context):
_statusChat.open_group_chat_edit_popup() _statusChat.send_gif()
@When("the user types \"|any|\"") @When("the user presses enter")
def step(context, message):
_statusChat.type_message_in_chat_input(message)
@When("the user changes the group name to |any|")
def step(context, groupName):
_statusChat.group_chat_edit_name(groupName)
@When("the user changes the group color to |any|")
def step(context, groupColor):
_statusChat.group_chat_edit_color(groupColor)
@When("the user changes the group image")
def step(context): def step(context):
_statusChat.group_chat_edit_image(context.userData["fixtures_root"]) _statusChat.press_enter()
@When("the user inputs a mention to |any| with message |any|")
def step(context,displayName,message):
_statusChat.send_message_with_mention(displayName, message)
@When("the user sends the emoji |any| as a message")
def step(context, emoji_short_name):
_statusChat.send_emoji(emoji_short_name, "")
@When("the user sends the emoji |any| with message |any|")
def step(context, emoji_short_name, message):
_statusChat.send_emoji(emoji_short_name, message)
# Using position of sticker because stickers don't have ids, only hashes and it feels weird to type hashes in Gherkin
@When("the user sends the sticker at position |any| in the list")
def step(context, sticker_index):
_statusChat.send_sticker(sticker_index)
@When("the user sends a random chat message")
def step(context):
random_int = randint(0, 10000)
message = "random message " + str(random_int)
_statusChat.send_message(message)
context.userData["randomMessage"] = message
@When("the user switches to |any| chat")
def step(context, chatName):
_statusChat.switch_to_chat(chatName)
@When("the user creates a group chat adding users")
def step(context):
the_user_creates_a_group_chat_adding_users(context)
@When("the user saves changes") @When("the user saves changes")
def step(context): def step(context):
_statusChat.group_chat_edit_save() _statusChat.group_chat_edit_save()
@When("the user pressed enter") @When("the user leaves current chat")
def step(context): def step(context):
_statusChat.press_enter_in_chat_input() _statusChat.leave_chat()
@Then("user is able to send chat message") #########################
def step(context): ### VERIFICATIONS region:
table = context.table #########################
for row in table[1:]:
_statusChat.send_message(row[0])
_statusChat.verify_last_message_sent(row[0])
@Then("The user is able to send a gif message") @Then("the last chat message contains |any|")
def step(context):
_statusChat.send_gif()
_statusChat.verify_last_message_sent("tenor.gif")
@When("the user opens app settings screen from chat")
def step(context):
_statusChat.open_settings_from_message()
@Then("the image |any| is unfurled in the chat")
def step(context: any, image_link: str):
_statusChat.verify_image_unfurled_status(image_link, True)
@Then("the image |any| is not unfurled in the chat")
def step(context: any, image_link: str):
_statusChat.verify_image_unfurled_status(image_link, False)
@Then("the user selects emoji in the suggestion list")
def step(contenxt):
_statusChat.select_the_emoji_in_suggestion_list()
@Then("the user is able to send chat message \"|any|\"")
def step(context, message): def step(context, message):
_statusChat.send_message(message)
@When("the user sends the chat message |any|")
def step(context, message):
_statusChat.send_message(message)
_statusChat.verify_last_message_sent(message) _statusChat.verify_last_message_sent(message)
@Then("the user is able to send a random chat message") @Then("the chat message |any| is displayed as a reply")
def step(context): def step(context, message):
random_int = randint(0, 10000) # TODO: Check the last message is really a reply.
message = "random message " + str(random_int)
_statusChat.send_message(message)
_statusChat.verify_last_message_sent(message) _statusChat.verify_last_message_sent(message)
context.userData["randomMessage"] = message
@Then("the chat message |any| is displayed as an edited one")
def step(context, message):
# TODO: Check last message is an edited one.
_statusChat.verify_last_message_sent(message)
@Then("the last message displayed is not |any|")
def step(context, message):
_statusChat.verify_last_message_sent_is_not(message)
@Then("the chat is cleared") @Then("the chat is cleared")
def step(context): def step(context):
_statusChat.verify_last_message_is_not_loaded() _statusChat.verify_last_message_is_not_loaded()
@Then("the GIF message is displayed")
def step(context):
# TODO: It should be a specific verification call instead of adding here a string (Screen layer responsibility)
_statusChat.verify_last_message_sent("tenor.gif")
@Then("the image |any| is unfurled in the chat")
def step(context: any, image_link: str):
_statusChat.verify_image_unfurled_status(image_link, True)
@Then("the user cannot delete the last message")
def step(context):
_statusChat.cannot_delete_last_message()
@Then("the |any| mention with message |any| have been sent")
def step(context,displayName,message):
_statusChat.verify_last_message_sent_contains_mention(displayName, message)
@Then("the user cannot input a mention to a not existing user |any|")
def step(context, displayName):
_statusChat.cannot_do_mention(displayName)
@Then("the last chat message is a sticker")
def step(context):
_statusChat.verify_last_message_is_sticker()
@Then("the user chats are sorted accordingly")
def step(context):
table = context.table
for i, row in enumerate(table):
chatName = row[0]
_statusChat.verify_chat_order(i, chatName)
@Then("the random chat message is displayed")
def step(context):
message = context.userData["randomMessage"]
_statusChat.verify_last_message_sent(message)
@Then("the group chat is created") @Then("the group chat is created")
def step(context): def step(context):
_statusChat = StatusChatScreen() the_group_chat_is_created()
@Then("the group chat history contains \"|any|\" message")
def step(context, createdTxt):
_statusChat.verify_chat_created_message_is_displayed_in_history(createdTxt)
@Then("the chat title is |any|") @Then("the chat title is |any|")
def step(context, title): def step(context, title):
@ -129,95 +229,20 @@ def step(context, color):
def step(context): def step(context):
_statusChat.verify_chat_image(context.userData["fixtures_root"]) _statusChat.verify_chat_image(context.userData["fixtures_root"])
@Then("the group chat contains the following members") @Then("the chat |any| does not exist")
def step(context):
_statusChat.verify_members_added(context.table)
@Then("the group chat is up to chat sending \"|any|\" message")
def step(context, message):
_statusChat.send_message(message)
_statusChat.verify_last_message_sent(message)
@Then("the user can reply to the message at index |any| with \"|any|\"")
def step(context, message_index, message):
_statusChat.reply_to_message_at_index(message_index, message)
_statusChat.verify_last_message_sent(message)
@When("the user edits the message at index |any| and changes it to \"|any|\"" )
def step(context, message_index, message):
_statusChat.edit_message_at_index(message_index, message)
_statusChat.verify_last_message_sent(message)
@Then("the user can mark the channel |any| as read")
def step(context, channel):
_statusMain.mark_as_read(channel)
@Then("the user can delete the message at index |any|")
def step(context, message_index):
_statusChat.delete_message_at_index(message_index)
time.sleep(1)
@Then("the user cannot delete the last message")
def step(context):
_statusChat.cannot_delete_last_message()
@Then("the last message is not \"|any|\"")
def step(context, message):
_statusChat.verify_last_message_sent_is_not(message)
@Then("the last message is not the random message")
def step(context):
_statusChat.verify_last_message_sent_is_not(context.userData["randomMessage"])
@When("user sends the emoji |any| as a message")
def step(context, emoji_short_name):
_statusChat.send_emoji(emoji_short_name, "")
@When("user sends the emoji |any| with message |any|")
def step(context, emoji_short_name, message):
_statusChat.send_emoji(emoji_short_name, message)
@Then("the emoji |any| is displayed in the last message")
def step(context, emoji):
_statusChat.verify_last_message_sent(emoji)
@Then("the message |any| is displayed in the last message")
def step(context, message):
_statusChat.verify_last_message_sent(message)
@Then("the user can install the sticker pack at position |any|")
def step(context, pack_index):
_statusChat.install_sticker_pack(pack_index)
# Using position of sticker because stickers don't have ids, only hashes and it feels weird to type hashes in Gherkin
@Then("the user can send the sticker at position |any| in the list")
def step(context, sticker_index):
_statusChat.send_sticker(sticker_index)
@Then("the user cannot input a mention to a not existing user |any|")
def step(context, displayName):
_statusChat.cannot_do_mention(displayName)
@Then("the |any| mention with message |any| have been sent")
def step(context,displayName,message):
_statusChat.verify_last_message_sent_contains_mention(displayName, message)
@Then("user chats are sorted accordingly")
def step(context):
table = context.table
for i, row in enumerate(table):
chatName = row[0]
_statusChat.verify_chat_order(i, chatName)
@When("user switches to |any| chat")
def step(context, chatName):
_statusChat.switch_to_chat(chatName)
@When("the user leaves current chat")
def step(context):
_statusChat.leave_chat()
@Then("chat |any| does not exist")
def step(context, chatName): def step(context, chatName):
_statusMain.verify_chat_does_not_exist(chatName) _statusMain.verify_chat_does_not_exist(chatName)
###########################################################################
### COMMON methods used in different steps given/when/then region:
###########################################################################
def the_user_sends_a_chat_message(message: str):
_statusChat.send_message(message)
def the_user_creates_a_group_chat_adding_users(context: any):
_statusMain.open_start_chat_view()
_statusCreateChatView.create_chat(context.table)
def the_group_chat_is_created():
_statusChat = StatusChatScreen()

View File

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# This file contains hook functions to run as the .feature file is executed
sys.path.append(os.path.join(os.path.dirname(__file__), "../../../testSuites/global_shared/"))
sys.path.append(os.path.join(os.path.dirname(__file__), "../../../src/"))
from steps.startupSteps import *
# Global properties for the specific feature
_user = "tester123"
_password = "TesTEr16843/!@00"
_chat_room = "test"
@OnFeatureStart
def hook(context):
context_init(context)
signs_up_process_steps(context, _user, _password)
when_the_user_joins_chat_room(_chat_room)
@OnFeatureEnd
def hook(context):
currentApplicationContext().detach()
snooze(_app_closure_timeout)
@OnScenarioStart
def hook(context):
when_the_user_opens_the_chat_section()
@OnStepEnd
def hook(context):
context.userData["step_name"] = context._data["text"]

View File

@ -1,169 +1,175 @@
# This is a sample .feature file Feature: Status Desktop Chat Basic Flows
# Squish feature files use the Gherkin language for describing features, a short example
# is given below. You can find a more extensive introduction to the Gherkin format at
# https://cucumber.io/docs/gherkin/reference/
Feature: Status Desktop Chat
# TODO The complete feature / all scenarios have a chance to fail since they rely on the mailserver (at least, to verify a chat is loaded, something in the history needs to be displayed). As a user I want to join the public chat room "test" and do basic interactions.
As a user I want to join a room and chat and do basic interactions.
The following scenarios cover basic chat flows. The following scenarios cover basic chat flows on "test" public channel.
Background: 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 ** 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 ** when user signs up with username "tester123" and password "TesTEr16843/!@00"
Then the user lands on the signed in app ** and the user lands on the signed in app
** and user joins chat room "test"
Scenario: User joins a public room and chats [Cleanup] Also each scenario starts with:
When user joins chat room test ** when the user opens the chat section
Then user is able to send chat message # TODO: Add scenario end -> clear chat input.
Scenario Outline: The user can chat in a public room
When the user sends a chat message <message>
Then the last chat message contains <message>
Examples:
| message | | message |
| Hello | | Hello |
| How are you | | How are you |
| I am from status | | I am from status |
| tell me how you do? | | tell me how you do? |
@merge # TODO: Scenario: The user can reply to their OWN message
Scenario: User can reply to their own message @mayfail
When user joins chat room test # TODO: It works standalone but when it runs as part of the sequence, the action of reply is not done always. The popup option does not appear.
Then the user is able to send a random chat message Scenario Outline: The user can reply to the last message
Then the user can reply to the message at index 0 with "This is a reply" Given the user sends a chat message <message>
When the user replies to the message at index 0 with <reply>
# TODO: Check the last message is really a reply, now just checking the last message is the expected one but could not be a reply. The popup option does not appear.
Then the chat message <reply> is displayed as a reply
Examples:
| message | reply |
| random chat message | This is a reply |
@merge @mayfail
Scenario: User can edit a message # TODO: It works standalone but when it runs as part of the sequence, the action of edit is not done always. The popup option does not appear.
When user joins chat room test Scenario Outline: The user can edit a message
Then user is able to send chat message Given the user sends a chat message <message>
| message | When the user edits the message at index 0 and changes it to <edited>
| Edit me | # TODO: Check last message is an edited one, now just checking the last message is the expected one but could not be an edited one.
When the user edits the message at index 0 and changes it to "Edited by me" Then the chat message <edited> is displayed as an edited one
Then the message (edited) is displayed in the last message Examples:
| message | edited |
| Edit me | Edited by me |
@relyon-mailserver
Scenario Outline: The user can reply to another message
When the user replies to the message at index 0 with <reply>
Then the chat message <reply> is displayed as a reply
Examples:
| reply |
| This is a reply |
@mayfail @merge # TODO: This scenario should be extracted to a different feature file bc it doesn't accomplish the background steps since it needs to change/specify the chat room
Scenario: User can reply to another user's message # Scenario Outline: The user joins a room and marks it as read
When user joins chat room test # When the user joins chat room test
Then the user can reply to the message at index 0 with "This is a reply to another user" # And the user marks the channel <channel> as read
# # TODO find a way to validate that it worked
# Examples:
# | channel |
# | test |
@mayfail @merge @mayfail
Scenario: User joins a room and marks it as read # TODO: It works standalone but when it runs as part of the sequence, the action of delete is not done always. The popup option does not appear.
When user joins chat room test Scenario Outline: The user can delete his/her own message
Then the user can mark the channel test as read Given the user sends a chat message <message>
# TODO find a way to validate that it worked When the user deletes the message at index 0
Then the last message displayed is not <message>
Examples:
| message |
| random chat message |
@merge Scenario: The user can clear chat history
Scenario: User can delete their own message Given the user sends a chat message Hi hi
When user joins chat room automation-test And the user sends a chat message testing chat
Then the user is able to send a random chat message And the user sends a chat message history
Then the user can delete the message at index 0
Then the last message is not the random message
@merge
Scenario: User can clear chat history
When user joins chat room test
Then user is able to send chat message
| message |
| Hello |
| How are you |
| I am from status |
| tell me how you do? |
When the user clears chat history When the user clears chat history
Then the chat is cleared Then the chat is cleared
@mayfail @merge @mayfail
Scenario: User can send a gif # TODO: Verification of gif sent fails. And also `tenor GIFs preview is enabled` step doesn't work. Review it.
When the user opens the chat section Scenario: The user can send a GIF
And user joins chat room automation-test Given the user opens app settings screen
Then The user is able to send a gif message And the user opens the messaging settings
When the user opens app settings screen And tenor GIFs preview is enabled
And the user opens the messaging settings When the user sends a GIF message
Then tenor GIFs preview is enabled Then the GIF message is displayed
@mayfail @merge @mayfail
Scenario Outline: User can activate image unfurling # TODO: It works standalone but when it runs as part of the sequence, the action of activates link preview doesn't work.
When the user opens the chat section Scenario Outline: The user can activate image unfurling
And user joins chat room automation-test Given the user sends a chat message <image_url>
And the user sends the chat message <image_url> And the image <image_url> is not unfurled in the chat
Then the image <image_url> is not unfurled in the chat When the user opens app settings screen
When the user opens app settings screen from chat And the user opens the messaging settings
And the user opens the messaging settings And the user activates link preview
And the user activates link preview And the user activates image unfurling
And the user activates image unfurling And the user opens the chat section
And the user opens the chat section Then the image <image_url> is unfurled in the chat
Then the image <image_url> is unfurled in the chat Examples:
| image_url |
| https://github.com/status-im/status-desktop/raw/master/test/ui-test/fixtures/images/doggo.jpeg |
Examples: Scenario Outline: The user is able to use emoji suggestions
| image_url | Given the user types <message>
| https://github.com/status-im/status-desktop/raw/master/test/ui-test/fixtures/images/doggo.jpeg | And the user selects the emoji in the suggestion's list
When the user presses enter
Then the last chat message contains <emoji>
Examples:
| message | emoji |
| hello :thumbs | 👍 |
@mayfail @merge @relyon-mailserver
Scenario: The user is able to use emoji suggestions Scenario: The user cannot delete another user's message
When user joins chat room automation-test
When the user types "hello :thumbs"
Then the user selects emoji in the suggestion list
When the user pressed enter
Then the message 👍 is displayed in the last message
@mayfail @merge
Scenario: User cannot delete another user's message
When user joins chat room test
Then the user cannot delete the last message Then the user cannot delete the last message
@relyon-mailserver
@mayfail @merge
Scenario Outline: The user can do a mention Scenario Outline: The user can do a mention
When user joins chat room test When the user inputs a mention to <displayName> with message <message>
And the user inputs a mention to <displayName> with message <message>
Then the <displayName> mention with message <message> have been sent Then the <displayName> mention with message <message> have been sent
Examples: Examples:
| displayName | message | | displayName | message |
| tester123 | testing mention | | tester123 | testing mention |
@relyon-mailserver
@mayfail @merge Scenario Outline: The user can not do a mention to a not existing users
Scenario Outline: The user can not do a mention to not existing users
When user joins chat room test
Then the user cannot input a mention to a not existing user <displayName> Then the user cannot input a mention to a not existing user <displayName>
Examples: Examples:
| displayName | | displayName |
| notExistingAccount | | notExistingAccount |
| asdfgNoNo | | asdfgNoNo |
@mayfail @merge Scenario: The user can send an emoji as a message
Scenario: User can send an emoji in a message When the user sends the emoji heart_eyes as a message
When user joins chat room automation-test Then the last chat message contains 😍
When user sends the emoji heart_eyes as a message
Then the emoji 😍 is displayed in the last message
When user sends the emoji sunglasses with message wow I'm so cool
Then the emoji 😎 is displayed in the last message
And the message wow I'm so cool is displayed in the last message
@merge Scenario Outline: The user can send an emoji in a message
Scenario: User sees chats sorted by most recent activity When the user sends the emoji sunglasses with message <message>
When user joins chat room first-chat Then the last chat message contains 😎
And user joins chat room second-chat And the last chat message contains <message>
And user joins chat room third-chat Examples:
Then user chats are sorted accordingly | message |
| third-chat | | wow I'm so cool |
| second-chat |
| first-chat |
When user switches to second-chat chat
Then the user is able to send a random chat message
And user chats are sorted accordingly
| second-chat |
| third-chat |
| first-chat |
@mayfail @merge # TODO: This scenario should be extracted to a different feature file bc it doesn't accomplish the background steps since it needs to change/specify the chat room
Scenario: User can type message with emoji autoreplace # @merge
When user joins chat room automation-test # Scenario: The user sees chats sorted by most recent activity
Then the user is able to send chat message "Hello :)" # When the user joins chat room first-chat
Then the message 🙂 is displayed in the last message # And the user joins chat room second-chat
And the message Hello is displayed in the last message # And the user joins chat room third-chat
# Then the user chats are sorted accordingly
# | third-chat |
# | second-chat |
# | first-chat |
# When the user switches to second-chat chat
# And the user sends a random chat message
# Then the random chat message is displayed
# And the user chats are sorted accordingly
# | second-chat |
# | third-chat |
# | first-chat |
Scenario: The user can type message with emoji autoreplace
When the user sends a chat message Hello :)
Then the last chat message contains 🙂
And the last chat message contains Hello
@merge Scenario: The user can send a sticker after installing a free pack
Scenario: User can send a sticker after installing a free pack Given the user installs the sticker pack at position 4
When user joins chat room automation-test When the user sends the sticker at position 2 in the list
Then the user can install the sticker pack at position 4 Then the last chat message is a sticker
Then the user can send the sticker at position 2 in the list

View File

@ -1,6 +1,6 @@
source(findFile('scripts', 'python/bdd.py')) source(findFile('scripts', 'python/bdd.py'))
setupHooks('../../global_shared/scripts/bdd_hooks.py') setupHooks('bdd_hooks.py')
collectStepDefinitions('./steps', '../shared/steps/', '../../global_shared/steps/', '../../suite_onboarding/shared/steps/') collectStepDefinitions('./steps', '../shared/steps/', '../../global_shared/steps/', '../../suite_onboarding/shared/steps/')
def main(): def main():

View File

@ -2,63 +2,72 @@ Feature: Status Desktop Group Chat
As a user I want to use group chat functionality. As a user I want to use group chat functionality.
The feature start sequence follows the global one (setup on global `bdd_hooks`):
Background: Background:
Given the user starts the application with a specific data folder ../../../fixtures/group_chat Given the user starts the application with a specific data folder ../../../fixtures/group_chat
When the user tester123 logs in with password TesTEr16843/!@00 When the user tester123 logs in with password TesTEr16843/!@00
Then the user lands on the signed in app Then the user lands on the signed in app
@mayfail @relyon-mailserver
Scenario: As an admin user I want to create a group chat with my contacts and the invited users can send messages Scenario Outline: As an admin user I want to create a group chat with my contacts and the invited users can send messages
When the user creates a group chat adding users Given the user creates a group chat adding users
| Athletic | | Athletic |
| Nervous | | Nervous |
Then the group chat is created And the group chat is created
And the group chat history contains "created the group" message And the group chat history contains "created the group" message
And the chat title is Athletic&Nervous
And the group chat contains the following members And the group chat contains the following members
| Athletic | | Athletic |
| Nervous | | Nervous |
And the group chat is up to chat sending "Admin user message sent" message
When the user sends a chat message <message1>
Then the chat title is Athletic&Nervous
And the last chat message contains <message1>
# Invited user 1 # Invited user 1
When the user restarts the app Given the user restarts the app
And the user Nervous logs in with password TesTEr16843/!@00 And the user Nervous logs in with password TesTEr16843/!@00
Then the user lands on the signed in app And the user lands on the signed in app
When the user clicks on Athletic&Nervous chat And the user clicks on Athletic&Nervous chat
Then the group chat is up to chat sending "Invited user 1 message sent!!" message When the user sends a chat message <message2>
Then the last chat message contains <message2>
# Invited user 2 # Invited user 2
When the user restarts the app Given the user restarts the app
And the user Athletic logs in with password TesTEr16843/!@00 And the user Athletic logs in with password TesTEr16843/!@00
Then the user lands on the signed in app And the user lands on the signed in app
When the user clicks on Athletic&Nervous chat And the user clicks on Athletic&Nervous chat
Then the group chat is up to chat sending "Invited user 2 message sent!!" message When the user sends a chat message <message3>
Then the last chat message contains <message3>
Examples:
| message1 | message2 | message3 |
| Admin user message sent | Invited user 1 message sent!! | Invited user 2 message sent!! |
# TODO: Add cleanup scenario. Leave, one by one, the chat # TODO: Add cleanup scenario. Leave, one by one, the chat
@mayfail @merge
Scenario: As an admin user I want to change group chat's name, color and image Scenario: As an admin user I want to change group chat's name, color and image
When the user creates a group chat adding users When the user creates a group chat adding users
| Athletic | | Athletic |
| Nervous | | Nervous |
Then the group chat is created Then the group chat is created
When the user opens the edit group chat popup Given the user opens the edit group chat popup
And the user changes the group name to Fat&Lazy And the user changes the group name to Fat&Lazy
And the user saves changes When the user saves changes
Then the chat title is Fat&Lazy Then the chat title is Fat&Lazy
When the user opens the edit group chat popup Given the user opens the edit group chat popup
And the user changes the group color to #7CDA00 And the user changes the group color to #7CDA00
And the user saves changes When the user saves changes
Then the chat color is #7CDA00 Then the chat color is #7CDA00
When the user opens the edit group chat popup Given the user opens the edit group chat popup
And the user changes the group image And the user changes the group image
And the user saves changes When the user saves changes
Then the chat image is changed Then the chat image is changed
When the user leaves current chat When the user leaves current chat
Then chat Fat&Lazy does not exist Then the chat Fat&Lazy does not exist

View File

@ -2,10 +2,31 @@ from screens.StatusLoginScreen import StatusLoginScreen
_loginScreen = StatusLoginScreen() _loginScreen = StatusLoginScreen()
#########################
### PRECONDITIONS region:
#########################
@Given("the user |any| logs in with password |any|")
def step(context, username, password):
the_user_any_logs_in_with_password(username, password)
#########################
### ACTIONS region:
#########################
@When("the user |any| logs in with password |any|") @When("the user |any| logs in with password |any|")
def step(context, username, password): def step(context, username, password):
_loginScreen.login(username, password) the_user_any_logs_in_with_password(username, password)
#########################
### VERIFICATIONS region:
#########################
@Then("the user is NOT able to login to Status Desktop application") @Then("the user is NOT able to login to Status Desktop application")
def step(context): def step(context):
_loginScreen.verify_error_message_is_displayed() _loginScreen.verify_error_message_is_displayed()
###########################################################################
### COMMON methods used in different steps given/when/then region:
###########################################################################
def the_user_any_logs_in_with_password(username: str, password: str):
_loginScreen.login(username, password)

View File

@ -1,29 +1,33 @@
from steps.startupSteps import *
from screens.StatusWelcomeScreen import StatusWelcomeScreen from screens.StatusWelcomeScreen import StatusWelcomeScreen
from screens.StatusMainScreen import StatusMainScreen from screens.StatusMainScreen import StatusMainScreen
_welcomeScreen = StatusWelcomeScreen() _welcomeScreen = StatusWelcomeScreen()
_mainScreen = StatusMainScreen() _mainScreen = StatusMainScreen()
#########################
### PRECONDITIONS region:
#########################
@Given("A first time user lands on the status desktop and generates new key") @Given("A first time user lands on the status desktop and generates new key")
def step(context): def step(context):
erase_directory(context.userData["status_data_folder_path"]) given_a_first_time_user_lands_on_and_generates_new_key(context)
startApplication(context.userData["aut_name"])
_welcomeScreen.agree_terms_conditions_and_generate_new_key()
@Given("A first time user lands on the status desktop and navigates to import seed phrase") @Given("A first time user lands on the status desktop and navigates to import seed phrase")
def step(context): def step(context):
erase_directory(context.userData["status_data_folder_path"]) given_a_first_time_user_lands_on_and_navigates_to_import_seed_phrase(context)
startApplication(context.userData["aut_name"])
_welcomeScreen.agree_terms_conditions_and_navigate_to_import_seed_phrase()
@Given("the user lands on the signed in app")
def step(context):
when_the_user_lands_on_the_signed_in_app()
#########################
### ACTIONS region:
#########################
@When("user signs up with username |any| and password |any|") @When("user signs up with username |any| and password |any|")
def step(context, username, password): def step(context, username, password):
_welcomeScreen.input_username_and_password_and_finalize_sign_up(username, password) when_the_user_signs_up(username, password)
@When("the user inputs username |any|") @When("the user inputs username |any|")
def step(context, username): def step(context, username):
@ -33,26 +37,34 @@ def step(context, username):
def step(context, seed_phrase): def step(context, seed_phrase):
_welcomeScreen.input_seed_phrase(seed_phrase) _welcomeScreen.input_seed_phrase(seed_phrase)
@When("the user logs in with password |any|")
def step(context, password: str):
_welcomeScreen.enter_password(password)
@When("the user signs up with profileImage |any|, username |any| and password |any|")
def step(context, profileImageUrl, username, password):
_welcomeScreen.input_username_profileImage_password_and_finalize_sign_up("file:///"+context.userData["fixtures_root"]+"images/"+profileImageUrl, username, password)
@When("a screenshot of the profileImage is taken")
def step(context):
_welcomeScreen.grab_screenshot()
#########################
### VERIFICATIONS region:
#########################
@Then("the user lands on the signed in app") @Then("the user lands on the signed in app")
def step(context): def step(context):
_mainScreen.is_ready() when_the_user_lands_on_the_signed_in_app()
@Then("the invalid seed text is visible") @Then("the invalid seed text is visible")
def step(context): def step(context):
_welcomeScreen.seed_phrase_visible() _welcomeScreen.seed_phrase_visible()
@When("the user logs in with password |any|")
def step(context, password: str):
_welcomeScreen.enter_password(password)
@Then("the user is online") @Then("the user is online")
def step(context): def step(context):
_mainScreen.user_is_online() _mainScreen.user_is_online()
@When("the user signs up with profileImage |any|, username |any| and password |any|")
def step(context, profileImageUrl, username, password):
_welcomeScreen.input_username_profileImage_password_and_finalize_sign_up("file:///"+context.userData["fixtures_root"]+"images/"+profileImageUrl, username, password)
@Then("my profile modal has the updated profile image") @Then("my profile modal has the updated profile image")
def step(context): def step(context):
_welcomeScreen.profile_modal_image_is_updated() _welcomeScreen.profile_modal_image_is_updated()
@ -61,13 +73,13 @@ def step(context):
def step(context): def step(context):
_welcomeScreen.profile_settings_image_is_updated() _welcomeScreen.profile_settings_image_is_updated()
@When("a screenshot of the profileImage is taken")
def step(context):
_welcomeScreen.grab_screenshot()
@Then("the profile navigation bar has the updated profile image") @Then("the profile navigation bar has the updated profile image")
def step(context): def step(context):
_welcomeScreen.profile_image_is_updated() _welcomeScreen.profile_image_is_updated()
delete_created_searchImage(context.userData["search_images"] +"profiletestimage.png") delete_created_searchImage(context.userData["search_images"] +"profiletestimage.png")
delete_created_searchImage(context.userData["search_images"]+"loginUserName.png") delete_created_searchImage(context.userData["search_images"]+"loginUserName.png")
###########################################################################
### COMMON methods used in different steps given/when/then region:
###########################################################################