diff --git a/actions.py b/actions.py index 90169dee641a28826ca2a0be910d226af504c513..d7034ee00d192cd64dd3bda40220f73694ed2889 100644 --- a/actions.py +++ b/actions.py @@ -1,5 +1,8 @@ import requests import json +import os +import re +from urllib.parse import quote from selenium.webdriver.common.by import By def click_sign_in(driver, logger, config): @@ -10,7 +13,7 @@ def click_sign_in(driver, logger, config): error_message = "Failed to load the Sign In button" logger.error(f"{error_message}: {e}") email_content = "<!DOCTYPE html><html lang='en'><body><p>Failed to load the Sign In button.</p><p>Steps to Reproduce:</p><ol><li>Navigate to the home page.</li><li>Wait to see if the Sign In button can be loaded.</li></ol></p></body></html>" - email_subject = "Error occured in the Home page" + email_subject = "Error occurred in the Home page" send_email(config, email_content, email_subject) def enter_name(driver, logger, config): @@ -53,35 +56,129 @@ def click_create_prototype(driver, logger): driver.find_element(By.XPATH, "//button[text()='Create New Prototype']").click() logger.debug("Clicked the Create New Prototype button") -def error_handler(logger, configInfo, error_message, exception, email_content, place_occur): - logger.error(f"{error_message}: {exception}") - instance = "local machine" - if ("autowrx-etas.digital.auto" in configInfo["web_url"]): - instance = "autowrx-etas.digital.auto" - email_subject = f"Error occured in the {place_occur} page of {instance}" - send_email(configInfo, email_content, email_subject) +def error_handler(level, logger, configInfo, error_message, exception, email_content, place_occur): + if (level == "critical"): + logger.critical(f"{error_message}: {exception}") + instance = get_instance_name(configInfo) + email_subject = f"A critical error occurred in the {place_occur} page of {instance}" + send_email(configInfo, email_content, email_subject, "now") + elif (level == "error"): + logger.error(f"{error_message}: {exception}") + elif (level == "warning"): + logger.warning(f"{error_message}: {exception}") -# Postman helper functions -def send_email(config, email_content, email_subject): - url = config["email_url"] - sending_obj = { - "to": config["developer_email"], - "subject": email_subject, - "content": email_content - } - requests.post(url, json = sending_obj) +def delete_testing_object(type, driver, logger, configInfo): + try: + # Get ID and token + if (type == "user"): + id = get_user_info(configInfo, "id", "signUp") + token = get_user_info(configInfo, "token", "admin") + else: + if (type == "model"): + pattern = r"model/([a-f0-9]{24})" + elif (type == "prototype"): + pattern = r"/prototype/([a-f0-9]{24})/" + current_url = driver.current_url + match = re.findall(pattern, current_url) + id = match[0] + token = get_user_info(configInfo, "token", "signIn") + + # Request for deletion + instance = get_instance_name(configInfo) + url = f"https://backend-core-{instance}.digital.auto/v2/{type}s/{id}" + headers = {"Authorization": f"Bearer {token}"} + response = requests.delete(url, headers=headers) + if response.content: + data = json.loads(response.content) + else: + data = {} + + # Check if the deletion is success + if (data == {}): + logger.info(f"Success. Deleted the testing {type} using Postman API.") + else: + raise Exception(f"Resulting JSON when deleting {type} is: {data}") -def get_user_info(config, element, mode): + except Exception as e: + error_handler("warning", logger, "", f"Failure. Cannot use Postman API to delete the testing {type}.", e, "", "") + +# Postman helper functions +def send_email(configInfo, email_content, email_subject, mode): + if (mode == "now"): + url = configInfo["email_url"] + sending_obj = { + "to": configInfo["developer_email"], + "subject": email_subject, + "content": email_content + } + requests.post(url, json = sending_obj) + elif (mode == "later"): + log_links = [] + for filename in os.listdir("logs"): + file_path = os.path.join("logs", filename) + if os.path.isfile(file_path): + if (check_warning_error(file_path) is True): + # Upload the log file and get the link + file_link = upload_file(file_path) + log_links.append(file_link) + + # Get the summary of the log file + with open(file_path, 'r') as file: + lines = file.readlines() + summary_index = None + for i, line in enumerate(lines): + if line.startswith("SUMMARY:"): + summary_index = i + break + if summary_index is not None: + summary_content = lines[summary_index:] + + if (len(log_links) > 0): + html_content = "<!DOCTYPE html><html lang='en'><body><p>Below are the summaries and links of the log files that report errors and warnings. Please click each link to see the details of the report.</p><ul>" + for i, link in enumerate(log_links, start=1): + html_content += f"<li><a href='{link}'>Log file {i}</a></li>" + for line in summary_content: + html_content += f"<br>{line}</br>" + html_content += "<br></br>" + html_content += "</ul></body></html>" + encoded_html_content = quote(html_content, safe='') + send_email(configInfo, encoded_html_content, email_subject, "now") + +def upload_file(file_path): + with open(file_path, 'rb') as file: + url = "https://upload.digitalauto.tech/upload/store-be" + files = {'file': (file_path, file, 'multipart/form-data')} + response = requests.post(url, files=files, verify=False) + data = json.loads(response.content) + return data["url"] # return the link to the document uploaded + +def get_instance_name(configInfo): + pattern = r"https://(.+?)\.digital\.auto/" + instance = re.findall(pattern, configInfo["web_url"]) + if (instance[0] == "autowrx"): + return "dev" + else: + return instance[0] + +def check_warning_error(file_path): + with open(file_path, "r") as file: + for line in file.readlines(): + if ("ERROR" in line) or ("WARNING" in line): + return True + return False + +def get_user_info(configInfo, element, mode): if (mode == "signIn"): - email = config["signIn_email"] - password = config["correct_password"] + email = configInfo["signIn_email"] + password = configInfo["correct_password"] elif (mode == "signUp"): - email = config["signUp_email"] - password = config["correct_password"] + email = configInfo["signUp_email"] + password = configInfo["correct_password"] elif (mode == "admin"): - email = config["admin_email"] - password = config["admin_password"] - url = "https://backend-core-etas.digital.auto/v2/auth/login" + email = configInfo["admin_email"] + password = configInfo["admin_password"] + instance = get_instance_name(configInfo) + url = f"https://backend-core-{instance}.digital.auto/v2/auth/login" sending_obj = {"email": email, "password": password} response = requests.post(url, json=sending_obj) data = json.loads(response.content) @@ -95,22 +192,4 @@ def get_user_info(config, element, mode): if "user" in data and "id" in data["user"]: return data["user"]["id"] else: - print("Unexpected response structure:", data) - -def delete_model(token, model_id): - url = f"https://backend-core-etas.digital.auto/v2/models/{model_id}" - headers = {"Authorization": f"Bearer {token}"} - requests.delete(url, headers=headers) - -def delete_prototype(token, prototype_id): - url = f"https://backend-core-etas.digital.auto/v2/prototypes/{prototype_id}" - headers = {"Authorization": f"Bearer {token}"} - requests.delete(url, headers=headers) - -def delete_user(admin_token, user_id): - url = f"https://backend-core-etas.digital.auto/v2/users/{user_id}" - headers = {"Authorization": f"Bearer {admin_token}"} - response = requests.delete(url, headers=headers) - # data = json.loads(response.content) - # return data - + print("Unexpected response structure:", data) \ No newline at end of file diff --git a/error.json b/error.json index f830fa1aa3a43874e3ab58d6bef86c32e8849522..897375d4de1528596430e9f178ed624b5e82ac71 100644 --- a/error.json +++ b/error.json @@ -1,34 +1,10 @@ { - "cannot_open_register_popup": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20to%20open%20the%20Register%20pop%20up.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3EClick%20the%20Sign%20In%20button%2C%20then%20click%20Register%3C%2Fli%3E%3Cli%3EWait%20to%20see%20if%20the%20Register%20pop%20up%20can%20be%20loaded.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "cannot_open_signIn_popup": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20to%20open%20the%20Sign%20In%20pop%20up.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3EClick%20the%20Sign%20In%20button%3C%2Fli%3E%3Cli%3EWait%20to%20see%20if%20the%20Sign%20In%20pop%20up%20can%20be%20loaded.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "cannot_register_account": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20to%20register%20an%20account.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3EClick%20the%20Sign%20In%20button%20and%20click%20the%20Register%20button%3C%2Fli%3E%3Cli%3EFill%20in%20all%20required%20fields%3C%2Fli%3E%3Cli%3EClick%20Register%20button%20to%20create%20an%20account%3C%2Fli%3E%3C%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "cannot_signIn": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20to%20sign%20in%20with%20valid%20password.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3EClick%20the%20Sign%20In%20button%3C%2Fli%3E%3Cli%3EFill%20in%20all%20correct%20information%20to%20sign%20In%20and%20click%20Sign%20In.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "cannot_logOut": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20to%20log%20out%20after%20signing%20in.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3ESign%20In%20with%20your%20account%3C%2Fli%3E%3Cli%3EClick%20the%20user%20icon%20and%20click%20logout.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", + "cannot_register_account": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20to%20register%20an%20account.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3EClick%20the%20Sign%20In%20button%20and%20click%20the%20Register%20button%3C%2Fli%3E%3Cli%3EFill%20in%20all%20required%20fields%3C%2Fli%3E%3Cli%3EClick%20Register%20button%20to%20create%20an%20account%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", "existing_email_passed": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20the%20test%20-%20existing%20email%20was%20used%20to%20sign%20up%20the%20account.%20Broken%20implementation.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3EClick%20the%20Sign%20In%20button%20and%20click%20the%20Register%20button%3C%2Fli%3E%3Cli%3EFill%20in%20all%20required%20fields%20but%20use%20an%20existing%20email%3C%2Fli%3E%3Cli%3EClick%20Register%20button%20to%20create%20an%20account%3C%2Fli%3E%3C%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", "incorrect_confirm_password": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20the%20test%20-%20confirm%20password%20was%20different%20from%20entered%20password.%20Broken%20implementation.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3EClick%20the%20Sign%20In%20button%20and%20click%20the%20Register%20button%3C%2Fli%3E%3Cli%3EFill%20in%20all%20required%20fields%20but%20enter%20a%20different%20password%20in%20the%20confirm%20password%20field%3C%2Fli%3E%3Cli%3EClick%20Register%20button%20to%20create%20an%20account%3C%2Fli%3E%3C%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", "empty_email_passed": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20the%20test%20-%20empty%20email%20field%20but%20can%20still%20registered.%20Broken%20implementation.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3EClick%20the%20Sign%20In%20button%20and%20click%20the%20Register%20button%3C%2Fli%3E%3Cli%3EFill%20in%20all%20required%20fields%20except%20the%20email%20field%3C%2Fli%3E%3Cli%3EClick%20Register%20button%20to%20create%20an%20account%3C%2Fli%3E%3C%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", "wrong_password_passed": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EWrong%20password%20passed.%20Broken%20implementation.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3EClick%20the%20Sign%20In%20button%3C%2Fli%3E%3Cli%3EEnter%20the%20correct%20email%20but%20wrong%20password.%3C%2Fli%3E%3Cli%3EClick%20Sign%20In%20to%20see%20if%20the%20wrong%20password%20is%20accepted%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", "not_signIn_see_CreateModel": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20the%20test.%20User%20did%20not%20sign%20in%20but%20can%20still%20see%20the%20'Create%20New%20Model'%20button.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3EDo%20not%20sign%20in%20and%20click%20the%20Select%20Model%20button%3C%2Fli%3E%3Cli%3EWait%20to%20see%20if%20there%20is%20the%20Create%20New%20Model%20button%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "empty_dropdown_CreateModel": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20the%20test.%20Empty%20option%20in%20the%20dropdown%20then%20creating%20a%20new%20model.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3ESign%20in%20and%20click%20Select%20Model%3C%2Fli%3E%3Cli%3EClick%20the%20Create%20New%20Model%2C%20check%20if%20the%20options%20in%20the%20pop%20up's%20dropdown%20is%20empty%20or%20not.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "empty_nameInput_passed_CreateModel": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20the%20test.%20Empty%20name%20field%20passed.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3ESign%20in%20and%20click%20Select%20Model%3C%2Fli%3E%3Cli%3EClick%20the%20Create%20New%20Model%2C%20leave%20the%20name%20field%20empty%20and%20click%20Create%20Model.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "wrong_newModel_name": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20the%20test.%20Entered%20new%20model%20name%20is%20different%20from%20resulting%20new%20model%20name.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3ESign%20in%20and%20click%20Select%20Model%3C%2Fli%3E%3Cli%3EClick%20the%20Create%20New%20Model%2C%20enter%20the%20name%20and%20click%20Create%20Model.%3C%2Fli%3E%3Cli%3EVerify%20the%20entered%20model%20name%20with%20the%20actual%20model%20name%20on%20the%20screen%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "empty_nameInput_passed_CreatePrototype": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20the%20test.%20Empty%20name%20field%20passed.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3ESign%20in%20and%20click%20Select%20Model%2C%20choose%20a%20model%20and%20click%20Prototype%20Library%3C%2Fli%3E%3Cli%3EClick%20the%20Create%20New%20Prototype%2C%20leave%20the%20name%20field%20empty%20and%20click%20Create.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "wrong_newPrototype_name": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20the%20test.%20Incorrect%20name%20of%20the%20newly%20created%20prototype%20on%20the%20right.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3ESign%20in%20and%20click%20Select%20Model%2C%20choose%20a%20model%20and%20click%20Prototype%20Library%3C%2Fli%3E%3Cli%3EClick%20the%20Create%20New%20Prototype%2C%20enter%20the%20name%20and%20click%20Create.%3C%2Fli%3E%3Cli%3EWait%20and%20see%20the%20prototype%20name%20on%20the%20prototype%20page%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", "cannotLoad_model": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20to%20load%20the%20model%20components%20in%20model%20page.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3EClick%20on%20the%20'Select%20Model'%20button.%3C%2Fli%3E%3Cli%3ECount%20the%20number%20of%20models%20to%20see%20if%20it's%20greater%20than%200.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "cannotLoad_prototype": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20to%20load%20the%20prototype%20components%20in%20home%20page.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3ECount%20the%20number%20of%20prototypes%20to%20see%20if%20it's%20greater%20than%200.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "cannotLoad_redPins": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20to%20load%20the%20red%20pins%20on%20the%20canvas.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3EClick%20on%20the%20'Select%20Model'%20button.%3C%2Fli%3E%3Cli%3EClick%20on%20the%20'ACME%20Car%20(EV)%20v0.1%20Model'%20image.%3C%2Fli%3E%3Cli%3EClick%20on%20the%20'Vehicle%20APIs'%20button.%3C%2Fli%3E%3Cli%3ECheck%20for%20the%20existence%20of%20red%20pins.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "cannotSwitchTo_public": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20to%20switch%20from%20private%20mode%20to%20public%20mode%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3EClick%20on%20the%20'Select%20Model'%20button.%3C%2Fli%3E%3Cli%3ECreate%20a%20new%20model%20and%20click%20the%20'Change%20to%20public'%20button%20to%20see%20if%20it%20switches%20to%20public%20mode.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "cannotSwitchTo_private": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20to%20switch%20from%20private%20mode%20to%20public%20mode%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3EClick%20on%20the%20'Select%20Model'%20button.%3C%2Fli%3E%3Cli%3ECreate%20a%20new%20model%20and%20click%20the%20'Change%20to%20public'%20button%20to%20see%20if%20it%20switches%20to%20public%20mode.%3C%2Fli%3E%3Cli%3EThen%20click%20'Change%20to%20private'%20button%20to%20see%20if%20it%20switches%20back%20to%20private%20mode.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "empty_userList_in_addUserButton": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20to%20switch%20from%20private%20mode%20to%20public%20mode%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3EClick%20on%20the%20'Select%20Model'%20button.%3C%2Fli%3E%3Cli%3ECreate%20a%20new%20model%20and%20click%20the%20'Add%20user'%20button%20to%20see%20if%20the%20list%20of%20user%20is%20empty%20or%20not.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "filter_list_in_addUser_isNotWorking": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EThe%20filter%20list%20in%20the%20add%20user%20pop%20up%20doesn't%20work%20properly.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3EClick%20on%20the%20'Select%20Model'%20button.%3C%2Fli%3E%3Cli%3ECreate%20a%20new%20model%20and%20click%20the%20'Add%20user'%20button.%3C%2Fli%3E%3Cli%3EThen%20type%20some%20characters%20in%20the%20search%20box%20to%20see%20if%20the%20filter%20list%20is%20working%20properly.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "Bosch_link_failed": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EThe%20Bosch%20Link%20in%20the%20Home%20page%20doesn't%20work%20properly.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3EScroll%20down%20and%20click%20the%20Bosch%20logo.%3C%2Fli%3E%3Cli%3EWait%20to%20see%20if%20it%20opens%20the%20correct%20webpage.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "Covesa_link_failed": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EThe%20Covesa%20Link%20in%20the%20Home%20page%20doesn't%20work%20properly.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3EScroll%20down%20and%20click%20the%20Covesa%20logo.%3C%2Fli%3E%3Cli%3EWait%20to%20see%20if%20it%20opens%20the%20correct%20webpage.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "Eclipse_link_failed": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EThe%20Eclipse%20Link%20in%20the%20Home%20page%20doesn't%20work%20properly.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3EScroll%20down%20and%20click%20the%20Eclipse%20logo.%3C%2Fli%3E%3Cli%3EWait%20to%20see%20if%20it%20opens%20the%20correct%20webpage.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "Ferdinand_Steinbeis_Institut_link_failed": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EThe%20Ferdinand%20Steinbeis%20Institut%20Link%20in%20the%20Home%20page%20doesn't%20work%20properly.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3EScroll%20down%20and%20click%20the%20Ferdinand%20Steinbeis%20Institut%20logo.%3C%2Fli%3E%3Cli%3EWait%20to%20see%20if%20it%20opens%20the%20correct%20webpage.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "addWidget_invalidBoxes": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3E'Add%20widget'%20button%20appeared%20when%20invalid%20boxes%20are%20selected%20in%20prototype%20page.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page%2C%20choose%20a%20prototype%20or%20create%20a%20new%20one.%3C%2Fli%3E%3Cli%3EOpen%20the%20prototype%20detail%20page%20and%20navigate%20to%20the%20Dashboard%20Config%20in%20Code%20section.%3C%2Fli%3E%3Cli%3EClick%20boxes%201%2C3%2C4%2C8%2C9%20and%20see%20if%20the%20'Add%20widget'%20button%20appears.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "addWidget_validBoxes": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3E'Add%20widget'%20button%20did%20not%20appear%20when%20valid%20boxes%20are%20selected%20in%20prototype%20page.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page%2C%20choose%20a%20prototype%20or%20create%20a%20new%20one.%3C%2Fli%3E%3Cli%3EOpen%20the%20prototype%20detail%20page%20and%20navigate%20to%20the%20Dashboard%20Config%20in%20Code%20section.%3C%2Fli%3E%3Cli%3EClick%20boxes%203%2C4%2C8%2C9%20and%20see%20if%20the%20'Add%20widget'%20button%20appears.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "addWidget_widgetList_empty": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3E'List%20of%20widgets%20is%20empty%20in%20the%20prototype%20page.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page%2C%20choose%20a%20prototype%20or%20create%20a%20new%20one.%3C%2Fli%3E%3Cli%3EOpen%20the%20prototype%20detail%20page%20and%20navigate%20to%20the%20Dashboard%20Config%20in%20Code%20section.%3C%2Fli%3E%3Cli%3EClick%20boxes%203%2C4%2C8%2C9%20and%20click%20'Add%20Widget'%20button.%3C%2Fli%3E%3Cli%3ECheck%20if%20the%20widget%20list%20is%20empty%20or%20not.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "addWidget_failed": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20to%20add%20a%20widget%20to%20the%20Dashboard%20Config%20in%20the%20prototype%20page.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page%2C%20choose%20a%20prototype%20or%20create%20a%20new%20one.%3C%2Fli%3E%3Cli%3EOpen%20the%20prototype%20detail%20page%20and%20navigate%20to%20the%20Dashboard%20Config%20in%20Code%20section.%3C%2Fli%3E%3Cli%3EClick%20boxes%203%2C4%2C8%2C9%20and%20click%20'Add%20Widget'%20button.%3C%2Fli%3E%3Cli%3EChoose%20the%20widget%20and%20click%20'Add%20selected%20widget'.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "editWidget_failed": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20to%20edit%20the%20widget%20config%20text%20in%20the%20prototype%20page.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page%2C%20choose%20a%20prototype%20or%20create%20a%20new%20one.%3C%2Fli%3E%3Cli%3EOpen%20the%20prototype%20detail%20page%20and%20navigate%20to%20the%20Dashboard%20Config%20in%20Code%20section.%3C%2Fli%3E%3Cli%3EClick%20boxes%20and%20add%20a%20new%20widget.%3C%2Fli%3E%3Cli%3EClick%20to%20edit%20the%20config%20text%20of%20the%20widget%2C%20save%20and%20see%20if%20there%20is%20an%20update%20in%20the%20'Show%20all%20raw%20config%20text'%20section.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E", - "deleteWidget_failed": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20to%20edit%20the%20widget%20in%20the%20prototype%20page.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page%2C%20choose%20a%20prototype%20or%20create%20a%20new%20one.%3C%2Fli%3E%3Cli%3EOpen%20the%20prototype%20detail%20page%20and%20navigate%20to%20the%20Dashboard%20Config%20in%20Code%20section.%3C%2Fli%3E%3Cli%3EClick%20boxes%20and%20add%20a%20new%20widget.%3C%2Fli%3E%3Cli%3EClick%20the%20delete%20icon.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E" + "cannotLoad_prototype": "%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D'en'%3E%3Cbody%3E%3Cp%3EFailed%20to%20load%20the%20prototype%20components%20in%20home%20page.%3C%2Fp%3E%3Cp%3ESteps%20to%20Reproduce%3A%3C%2Fp%3E%3Col%3E%3Cli%3ENavigate%20to%20the%20home%20page.%3C%2Fli%3E%3Cli%3ECount%20the%20number%20of%20prototypes%20to%20see%20if%20it's%20greater%20than%200.%3C%2Fli%3E%3C%2Fol%3E%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E" } \ No newline at end of file diff --git a/info.json b/info.json index b693896ae21311f089f2fa198a18bf5fcf5f2f40..28075994bed8944476256447f09b3bcb97d1a635 100644 --- a/info.json +++ b/info.json @@ -1,5 +1,5 @@ { - "web_url": "https://autowrx-etas.digital.auto/", + "web_url": "https://autowrx.digital.auto/", "email_url": "https://backend-core-dev.digital.auto/v2/emails", "test_file": "test_no_data.py", "developer_email": "vuy4hc@bosch.com", @@ -11,7 +11,7 @@ "admin_email": "dev@gmail.com", "admin_password": "abcd1234", "Bosch_link": "https://www.bosch.com/", - "Covesa_link": "https://covesa.global", + "Covesa_link": "https://www.covesa.global", "Eclipse_link": "https://www.eclipse.org", "Ferdinand_Steinbeis_Institut_link": "https://ferdinand-steinbeis-institut.de" } diff --git a/main.py b/main.py index 05dbac275a3b0ac3a357b4382b5a36f60db8ad0a..5125966f614a755208cb0c04dac288ecce5fd7ef 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,7 @@ import os +import json import argparse +from actions import send_email, get_instance_name def main(): parser = argparse.ArgumentParser( @@ -15,12 +17,17 @@ def main(): else: os.environ["HEADLESS"] = "false" - os.system("pytest -v -s --disable-warnings test_model.py") os.system("pytest -v -s --disable-warnings test_no_data.py") os.system("pytest -v -s --disable-warnings test_page_traversal.py") - # fixing the test_prototype, will include later os.system("pytest -v -s --disable-warnings test_signInOut.py") os.system("pytest -v -s --disable-warnings test_signUp.py") - + os.system("pytest -v -s --disable-warnings test_model.py") + os.system("pytest -v -s --disable-warnings test_prototype.py") + if __name__ == "__main__": - main() \ No newline at end of file + main() + with open('info.json') as config_file: + configInfo = json.load(config_file) + instance = get_instance_name(configInfo) + subject = f"[{instance}-instance] Warnings and errors occured" + send_email(configInfo, "", subject, "later") \ No newline at end of file diff --git a/set_up.py b/set_up.py index 1dde4a3a676258f76a22a85796f3211c36686f63..d70896d4a361f29c96c6e60d672e9353dfdd2b4f 100644 --- a/set_up.py +++ b/set_up.py @@ -67,19 +67,20 @@ class Base(): test_name = line[6:] if ("Success" in line) or ("Failure" in line): numOfTest += 1 - if ("ERROR" in line) or ("CRITICAL" in line): + if ("ERROR" in line) or ("CRITICAL" in line) or ("WARNING" in line): countFailed += 1 failed_tests.append(test_name) failed_tests.append(line[21:]) for handler in self.logger.handlers: if isinstance(handler, logging.FileHandler): + handler.stream.write(f"INSTANCE: {configInfo["web_url"]}\n") handler.stream.write("SUMMARY:\n") - handler.stream.write(f"\tNumber of failed test cases: {countFailed} / {numOfTest}\n") + handler.stream.write(f"\tNumber of FAILED test cases: {countFailed} / {numOfTest}\n") if (len(failed_tests) > 0): - handler.stream.write("Test cases that failed:\n") + handler.stream.write("\tTest cases that failed:\n") for i in range(0, len(failed_tests), 2): - handler.stream.write(f"\t{failed_tests[i]}") - handler.stream.write(f"\t\t{failed_tests[i+1]}") + handler.stream.write(f"\t\t{failed_tests[i]}") + handler.stream.write(f"\t\t\t{failed_tests[i+1]}") def start_timer(self): self.start_time = datetime.now() diff --git a/test_model.py b/test_model.py index e5ff1caae4400293ca57df44f914151fc259e918..7bf3e97aa8b2c7477fdb1dcc40f5f3011f578559 100644 --- a/test_model.py +++ b/test_model.py @@ -7,12 +7,9 @@ class Test_Model(BaseTest, unittest.TestCase): self.SignIn_createModel() # Also check the dropdown content inside this function self.check_modelVisibility() self.add_member_contributor() + self.create_wishlist_API() # NOT DONE - # Delete the testing model - token = get_user_info(self.configInfo, "token", "signIn") - current_url = self.driver.current_url - model_id = current_url[40:64] - delete_model(token, model_id) + delete_testing_object("model", self.driver, self.logger, self.configInfo) def noSignIn_createModel(self): self.base.beginOfTest_logFormat("noSignIn_createModel") @@ -24,7 +21,7 @@ class Test_Model(BaseTest, unittest.TestCase): try: createModel_button = self.driver.find_element(By.XPATH, "//button[contains(text(),'Create New Model')]") if (createModel_button.is_displayed()): - error_handler(self.logger, self.configInfo, "Failure. User did not sign in but can still see the 'Create New Model' button", + error_handler("critical", self.logger, self.configInfo, "Failure. User did not sign in but can still see the 'Create New Model' button", "", self.configError["not_signIn_see_CreateModel"], "Model") except: self.logger.info("Success. Tested the case of not seeing the 'Create New Model' button when not signing in") @@ -57,8 +54,7 @@ class Test_Model(BaseTest, unittest.TestCase): assert (message == '"name" is not allowed to be empty') self.logger.info("Success. Tested the case of empty input field when creating new model.") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Empty input name passed", e, - self.configError["empty_nameInput_passed_CreateModel"], "Model") + error_handler("error", self.logger, "", "Failure. Empty input name passed when creating a new model", e, "", "") # Hit Create New Model button and entering name try: @@ -71,11 +67,10 @@ class Test_Model(BaseTest, unittest.TestCase): wait.until(expected_conditions.visibility_of_element_located((By.XPATH, f"//label[text()='{expected_name}']"))) self.logger.debug("Created a new model") model_name = self.driver.find_element(By.XPATH, f"//label[text()='{expected_name}']").text - assert (model_name == 'Model "Automation Test Model" created successfully') + assert (model_name == expected_name or model_name == 'Model "Automation Test Model" created successfully') self.logger.info("Success. Verified the name of the new model") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Entered new model name is different from resulting new model name", e, - self.configError["wrong_newModel_name"], "Model") + error_handler("warning", self.logger, "Failure. Entered new model name is different from resulting new model name", e, "", "") def check_dropdownContent(self): self.base.beginOfTest_logFormat("check_dropdownContent") @@ -85,12 +80,13 @@ class Test_Model(BaseTest, unittest.TestCase): assert (len(options) > 0) self.logger.info("Success. Tested the dropdown content when creating a new model.") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Empty option in the dropdown then creating a new model", e, - self.configError["empty_dropdown_CreateModel"], "Model") + error_handler("error", self.logger, "", "Failure. Empty option in the dropdown then creating a new model", e, "", "") def check_modelVisibility(self): self.base.beginOfTest_logFormat("check_modelVisibility") self.logger.info("Test the visibility when click Change to public/private") + wait = WebDriverWait(self.driver, 2) + wait.until(expected_conditions.visibility_of_element_located((By.XPATH, "//label[text()='Visibility:']/label"))) current_mode = self.driver.find_element(By.XPATH, "//label[text()='Visibility:']/label").text visibility_button = self.driver.find_element(By.XPATH, "//button[contains(text(),'Change to')]") button_mode = visibility_button.text @@ -115,11 +111,9 @@ class Test_Model(BaseTest, unittest.TestCase): self.logger.info("Success. Switched successfully from public to private mode") time.sleep(3) except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Failed to switch from public mode to private mode", e, - self.configError["cannotSwitchTo_private"], "Model") + error_handler("error", self.logger, "", "Failure. Failed to switch from public mode to private mode", e, "", "") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Failed to switch from private mode to public mode", e, - self.configError["cannotSwitchTo_public"], "Model") + error_handler("error", self.logger, "", "Failure. Failed to switch from private mode to public mode", e, "", "") def add_member_contributor(self): self.base.beginOfTest_logFormat("add_member_contributor") @@ -127,12 +121,11 @@ class Test_Model(BaseTest, unittest.TestCase): self.driver.find_element(By.XPATH, "//button[normalize-space()='Add user']").click() try: - users = self.driver.find_elements(By.XPATH, "//div[@class='border-b border-slate-200 flex mt-2']") + users = self.driver.find_elements(By.XPATH, "//div[@class='border-b border-slate-200 flex']") assert (len(users) > 0) self.logger.info("Success. The list of user in the 'add user' pop up is not empty.") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. The list of user in the 'add user' pop up is empty.", e, - self.configError["empty_userList_in_addUserButton"], "Model") + error_handler("error", self.logger, "", "Failure. The list of user in the 'add user' pop up is empty.", e, "", "") try: search_box = self.driver.find_element(By.XPATH, "//input[@placeholder='Search']") self.search_user("my", "My") @@ -143,8 +136,7 @@ class Test_Model(BaseTest, unittest.TestCase): time.sleep(2) self.logger.info("Success. Found the correct user after typing characters in the search box.") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. The filter list in the add user pop up doesn't work properly.", e, - self.configError["filter_list_in_addUser_isNotWorking"], "Model") + error_handler("error", self.logger, "", "Failure. The filter list in the add user pop up doesn't work properly.", e, "", "") # Close the add user pop up to click other buttons self.driver.find_element(By.XPATH, "//button[text()='Close']").click() @@ -153,4 +145,10 @@ class Test_Model(BaseTest, unittest.TestCase): def search_user(self, input, expected_result): self.driver.find_element(By.XPATH, "//input[@placeholder='Search']").send_keys(input) result_text = self.driver.find_element(By.XPATH, "//div[@class='py-1 grow']/label").text - assert (result_text == expected_result) \ No newline at end of file + assert (result_text == expected_result) + + def create_wishlist_API(self): + self.driver.find_element(By.XPATH, "//div[text()='Vehicle APIs']").click() + time.sleep(2) + self.driver.find_element(By.XPATH, "//button[contains(., 'Add Wishlist API')]").click() + self.driver.find_element(By.XPATH, "//input[@name='name']").send_keys("Testing API") \ No newline at end of file diff --git a/test_no_data.py b/test_no_data.py index b014b8d4db612c66d63d0a7280c63cd7a654bd0f..59a90e836bb4873d7a8f32b80dfd41d3cdcee844 100644 --- a/test_no_data.py +++ b/test_no_data.py @@ -14,7 +14,7 @@ class Test_NoData(BaseTest, unittest.TestCase): assert (len(models) > 0) self.logger.info("Success. Tested the number of model components in model page") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Cannot load the model components in model page", e, + error_handler("critical", self.logger, self.configInfo, "Failure. Cannot load the model components in model page", e, self.configError["cannotLoad_model"], "Model") def count_numOf_prototypes(self): @@ -24,7 +24,7 @@ class Test_NoData(BaseTest, unittest.TestCase): assert (len(prototypes) > 0) self.logger.info("Success. Tested the number of prototype components in home page") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Cannot load the prototype components in home page", e, + error_handler("critical", self.logger, self.configInfo, "Failure. Cannot load the prototype components in home page", e, self.configError["cannotLoad_prototype"], "Home") # def count_numOf_redPins(self): @@ -41,6 +41,5 @@ class Test_NoData(BaseTest, unittest.TestCase): # assert (hidden_text == "7") # self.logger.info("Success tested the number of pins") # except Exception as e: - # error_handler(self.logger, self.configInfo, "Failure. Cannot load the red pins on the canvas", e, - # self.configError["cannotLoad_redPins"], "Vehicle APIs") + # error_handler("warning", self.logger, "", "Failure. Cannot load the red pins on the canvas", e, "", "") \ No newline at end of file diff --git a/test_page_traversal.py b/test_page_traversal.py index b01563dd8e15f03a2cd2ea125d5df692bbcd8bfc..8522858274fae18a641d2c29aabc909631a5630c 100644 --- a/test_page_traversal.py +++ b/test_page_traversal.py @@ -15,10 +15,11 @@ class Test_PageTraversal(BaseTest, unittest.TestCase): self.driver.find_element(By.XPATH, f"//a[@href='{page_url}']").click() windows_opened = self.driver.window_handles self.driver.switch_to.window(windows_opened[1]) - assert (page_url in self.driver.current_url) + pattern = r"https://(?:www\.)?([^/]+)" + match = re.findall(pattern, self.driver.current_url) + assert (match[0] in page_url) self.logger.info(f"Success. Opened and verified {name} Link") self.driver.close() self.driver.switch_to.window(windows_opened[0]) except Exception as e: - error_handler(self.logger, self.configInfo, f"Failure. Cannot open {name} Link in the Home Page", e, - self.configError[f"{name}_link_failed"], "Home") + error_handler("warning", self.logger, "", f"Failure. Cannot open {name} Link in the Home Page", e, "", "") diff --git a/test_prototype.py b/test_prototype.py index 406682ac34c247f7f46207e0b981abb272152d5f..32169b7907aa50178bed843dcd109c8783a0c933 100644 --- a/test_prototype.py +++ b/test_prototype.py @@ -1,3 +1,4 @@ +# NOT DONE from util import * class Test_Prototype(BaseTest, unittest.TestCase): @@ -15,22 +16,93 @@ class Test_Prototype(BaseTest, unittest.TestCase): self.check_widgetList_content() self.add_widget() self.use_Dashboard() + time.sleep(7) self.edit_widget() - # self.delete_widget() + time.sleep(3) + self.delete_widget() - # Delete the testing prototype - token = get_user_info(self.configInfo, "token", "signIn") - current_url = self.driver.current_url - prototype_id = current_url[83:107] - delete_prototype(token, prototype_id) + self.modifyCode_checkUpdate("from_Code_to_Dashboard") + self.run_code("no_error") + self.modifyCode_checkUpdate("from_Dashboard_to_Code") + # self.run_code("error") + + delete_testing_object("prototype", self.driver, self.logger, self.configInfo) + delete_testing_object("model", self.driver, self.logger, self.configInfo) + + def run_code(self, mode): + self.base.beginOfTest_logFormat(f"run_code_{mode}") + try: + static_dropdown = Select(self.driver.find_element(By.XPATH, "//select")) + static_dropdown.select_by_value("RunTime-VSS4.0-1970345") + self.logger.info("Success. The RunTime-VSS4.0-1970345 is online.") + except Exception as e: + error_handler("warning", self.logger, "", "Failure. The RunTime-VSS4.0-1970345 is not online.", e, "", "") + + if (mode == "no_error"): + try: + self.driver.find_element(By.XPATH, "(//div[@class='flex px-1 false']/button)[1]").click() + time.sleep(3) + output = self.driver.find_element(By.XPATH, "//p[contains(text(),'code 0')]") + assert (output.is_displayed()) + self.logger.info("Success. Run code successfully with exit code 0 in the Dashboard tab.") + except Exception as e: + error_handler("error", self.logger, "", "Failure. Failed to run code in the Dashboard tab.", e, "", "") + elif (mode == "error"): + try: + self.driver.find_element(By.XPATH, "(//div[@class='flex px-1 false']/button)[1]").click() + time.sleep(5) # wait for some output is printed + self.driver.find_element(By.XPATH, "(//div[@class='flex px-1 false']/button)[2]").click() + time.sleep(2) # wait for the error exit code to be appeared + # NOT DONE + # observe and grab the error exit code + except Exception as e: + error_handler("error", self.logger, "", "Failure. Failed to stop the executing code and return error exit code.", e, "", "") + + def modifyCode_checkUpdate(self, mode): + self.base.beginOfTest_logFormat(f"modifyCode_checkUpdate_{mode}") + if (mode == "from_Code_to_Dashboard"): + try: + code_block = self.driver.find_element(By.XPATH, "//div[@class='w-1/2 flex flex-col border-r']") + line = code_block.find_element(By.XPATH, ".//div[@class='line-numbers' and text()='30']") + line.click() + action1 = ActionChains(self.driver) + action1.key_down(Keys.CONTROL).send_keys('a').key_up(Keys.CONTROL).key_down(Keys.BACK_SPACE).send_keys('print("Automation Test")').perform() + time.sleep(2) # wait for the update in the Dashboard tab + self.driver.find_element(By.XPATH, "//a/div[text()='Dashboard']").click() + self.driver.find_element(By.XPATH, "//div[@class='flex']/button").click() + self.driver.find_element(By.XPATH, "//div[@class='flex']/div[text()='Code']").click() + time.sleep(3) + + result = self.driver.find_element(By.XPATH, "//div[@class='view-lines monaco-mouse-cursor-text']//span/span[text()='print']") + assert (result.text == "print") + self.logger.info("Success. Verified the code entered from Code tab in Dashboard tab.") + except Exception as e: + error_handler("error", self.logger, "", "Failure. The code entered in Code tab is not updated in Dashboard tab.", e, "", "") + elif (mode == "from_Dashboard_to_Code"): + try: + self.driver.find_element(By.XPATH, "//div[@class='flex']/div[text()='Code']").click() + time.sleep(3) + self.driver.find_element(By.XPATH, "//div[contains(@class, 'active-line-number')]").click() + action = ActionChains(self.driver) + action.key_down(Keys.BACK_SPACE).send_keys("for i in range(10):").key_down(Keys.ENTER).send_keys("print(i)").perform() + + time.sleep(3) # wait for the update in the Code tab + # NOT DONE + # go to the Code tab to check + # then go back to the Dashboard tab, click to open run code section + except Exception as e: + error_handler("error", self.logger, "", "Failure. The code entered in Dashboard tab is not updated in Code tab.", e, "", "") + def create_and_verify_prototypeName(self): self.base.beginOfTest_logFormat("create_and_verify_prototypeName") - - # Choose the Combustion Car model to create testing prototype time.sleep(3) click_select_model(self.driver, self.logger) - self.driver.find_element(By.XPATH, "//label[text()='Combustion Car']").click() + self.driver.find_element(By.XPATH, "//button[contains(text(),'Create New Model')]").click() + expected_name = "Automation Test Model" + self.driver.find_element(By.CSS_SELECTOR, "input[placeholder='Model Name']").send_keys(expected_name) + self.driver.find_element(By. XPATH, "//button[text()='Create Model']").click() + # self.driver.find_element(By.XPATH, "//label[text()='Combustion Car']").click() click_prototype_library(self.driver, self.logger) click_create_prototype(self.driver, self.logger) @@ -44,8 +116,7 @@ class Test_Prototype(BaseTest, unittest.TestCase): assert (message == '"name" is not allowed to be empty') self.logger.info("Success. Tested the case of empty input field when creating new prototype.") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Empty name field passed", e, - self.configError["empty_nameInput_passed_CreatePrototype"], "Model") + error_handler("error", self.logger, "", "Failure. Empty input name passed when creating a new prototype", e, "", "") # Hit Create New Prototype and entering name try: @@ -62,8 +133,7 @@ class Test_Prototype(BaseTest, unittest.TestCase): self.logger.debug("Clicked the prototype box") self.logger.info("Success. Verified the name of the newly created prototype on the left") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Incorrect name of the newly created prototype on the left", e, - self.configError["wrong_newPrototype_name"], "Model") + error_handler("warning", self.logger, "", "Failure. Incorrect name of the newly created prototype on the left", e, "", "") try: wait = WebDriverWait(self.driver, 2) @@ -72,8 +142,7 @@ class Test_Prototype(BaseTest, unittest.TestCase): assert (prototype_name_right == expected_name) self.logger.info("Success. Verified the name of the newly created prototype on the right") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Incorrect name of the newly created prototype on the right", e, - self.configError["wrong_newPrototype_name"], "Model") + error_handler("warning", self.logger, "", "Failure. Incorrect name of the newly created prototype on the right", e, "", "") def use_Code_dashboardConfig(self): self.base.beginOfTest_logFormat("use_Code_dashboardConfig") @@ -99,8 +168,7 @@ class Test_Prototype(BaseTest, unittest.TestCase): self.driver.find_element(By.XPATH, "//button[text()='Add widget']").click() self.logger.info("Success. The 'Add widget' button appeared when valid boxes are selected") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. 'Add widget' button did not appear when valid boxes are selected", e, - self.configError["addWidget_validBoxes"], "Prototype") + error_handler("error", self.logger, "", "Failure. 'Add widget' button did not appear when valid boxes are selected", e, "", "") def use_Dashboard(self): self.base.beginOfTest_logFormat("use_Dashboard") @@ -112,21 +180,21 @@ class Test_Prototype(BaseTest, unittest.TestCase): assert (widget_preview.is_displayed()) following_boxes = self.driver.find_elements(By.XPATH, "//div[@class='col-span-2 row-span-2']/following-sibling::*") preceeding_boxes = self.driver.find_elements(By.XPATH, "//div[@class='col-span-2 row-span-2']/preceding-sibling::*") - assert (len(preceeding_boxes) == 2 and len(following_boxes) == 7) + assert (len(preceeding_boxes) == 2 and len(following_boxes) == 4) self.logger.info("Success. Tested the Dashboard functionality to preview widget.") time.sleep(2) - except: - print("Error occured in Dashboard") + except Exception as e: + error_handler("error", self.logger, "", "Failure. Cannot see the preview of the widget in the Dashboard.", e, "", "") def check_widgetList_content(self): self.base.beginOfTest_logFormat("check_widgetList_content") try: + time.sleep(2) widgets = self.driver.find_elements(By.XPATH, "//div[@class='grow']/div/div") assert (len(widgets) > 0) self.logger.info("Success. The list of widgets is not empty.") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. List of widgets is empty.", e, - self.configError["addWidget_widgetList_empty"], "Prototype") + error_handler("error", self.logger, "", "Failure. List of widgets is empty.", e, "", "") def add_widget(self): self.base.beginOfTest_logFormat("add_widget") @@ -138,8 +206,7 @@ class Test_Prototype(BaseTest, unittest.TestCase): assert (widget_text == "Simple Wiper Widget") self.logger.info("Success. Added a widget to the Dashboard Config.") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Cannot add a widget to the Dashboard Config.", e, - self.configError["addWidget_failed"], "Prototype") + error_handler("error", self.logger, "", "Failure. Cannot add a widget to the Dashboard Config.", e, "", "") def delete_widget(self): self.base.beginOfTest_logFormat("delete_widget") @@ -147,13 +214,11 @@ class Test_Prototype(BaseTest, unittest.TestCase): action = ActionChains(self.driver) action.move_to_element(self.driver.find_element(By.XPATH, "//div[text()='Simple Wiper Widget']")).perform() self.driver.find_element(By.XPATH, "//button[@class='da-btn da-btn-destructive da-btn-md !px-0']//*[name()='svg']").click() - # self.driver.find_element(By.XPATH, "//div[text()='Delete widget']").click() alert_popup = self.driver.switch_to.alert alert_popup.accept() self.logger.info("Success. Deleted a widget in the Dashboard Config.") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Cannot delete a widget in the Dashboard Config.", e, - self.configError["deleteWidget_failed"], "Prototype") + error_handler("error", self.logger, "", "Failure. Cannot delete a widget in the Dashboard Config.", e, "", "") def edit_widget(self): self.base.beginOfTest_logFormat("edit_widget") @@ -174,11 +239,10 @@ class Test_Prototype(BaseTest, unittest.TestCase): action1.send_keys(Keys.ARROW_LEFT).perform() action2 = ActionChains(self.driver) action2.send_keys(Keys.ARROW_LEFT).perform() - time.sleep(1) # Small delay to ensure key press is registered - + time.sleep(1) # Small delay to ensure key press is pressed action3 = ActionChains(self.driver) action3.send_keys(" Testing").perform() - time.sleep(1) # Small delay to ensure key press is registered + time.sleep(1) action.move_to_element(self.driver.find_element(By.XPATH, "//button[contains(text(), 'Save')]")).perform() self.driver.find_element(By.XPATH, "//button[contains(text(), 'Save')]").click() @@ -199,11 +263,10 @@ class Test_Prototype(BaseTest, unittest.TestCase): found = True break if (found is False): - self.logger.debug("Did not find the span with text 'Builtin Testing'") + raise Exception("Did not find the span with text 'Builtin Testing'") else: assert (span.text == '"Builtin Testing"') self.logger.info("Success. Tested the case of editing the widget config text.") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Cannot edit the widget config text.", e, - self.configError["editWidget_failed"], "Prototype") \ No newline at end of file + error_handler("error", self.logger, "", "Failure. Cannot edit the widget config text.", e, "", "") \ No newline at end of file diff --git a/test_signInOut.py b/test_signInOut.py index 96e70108b786ccf20500f41809728163276f3432..799bc333c8754852f3e3b537f3f0a9f6ee5c917b 100644 --- a/test_signInOut.py +++ b/test_signInOut.py @@ -19,8 +19,7 @@ class Test_SignIn_SignOut(BaseTest, unittest.TestCase): canOpen_popUp = True self.logger.info("Success. Can open the sign in popup.") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Cannot open the Sign In pop up", e, - self.configError["cannot_open_signIn_popup"], "Home") + error_handler("error", self.logger, "", "Failure. Cannot open the Sign In pop up", e, "", "") return canOpen_popUp def signIn_invalid_password(self): @@ -35,8 +34,7 @@ class Test_SignIn_SignOut(BaseTest, unittest.TestCase): assert (login_error == "Incorrect email or password") self.logger.info("Success. Tested the invalid login attempt.") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Wrong password passed. Broken implementation", e, - self.configError["wrong_password_passed"], "Home") + error_handler("error", self.logger, "", "Failure. Wrong password passed. Broken implementation", e, "", "") def signIn_valid_password(self): @@ -49,9 +47,7 @@ class Test_SignIn_SignOut(BaseTest, unittest.TestCase): assert (user_icon.is_displayed()) self.logger.info("Success. Tested the valid login attempt.") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Cannot sign in with correct password. Broken implementation", e, - self.configError["cannot_signIn"], "Home") - + error_handler("error", self.logger, "", "Failure. Cannot sign in with correct password. Broken implementation", e, "", "") def logOut(self): self.base.beginOfTest_logFormat("logOut") @@ -68,5 +64,4 @@ class Test_SignIn_SignOut(BaseTest, unittest.TestCase): assert (signIn_button.is_displayed()) self.logger.info("Success. Tested logging out.") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Cannot log out after signing in.", e, - self.configError["cannot_logOut"], "Home") + error_handler("error", self.logger, "", "Failure. Cannot log out after signing in.", e, "", "") diff --git a/test_signUp.py b/test_signUp.py index b56c75033b1322015d95f11308f53ecfbae6495e..355e88b002a980777e773e11528d4169bdb0335d 100644 --- a/test_signUp.py +++ b/test_signUp.py @@ -11,6 +11,8 @@ class Test_SignUp(BaseTest, unittest.TestCase): self.signUp_fail_confirmPassword() time.sleep(2) self.signUp_success() + + delete_testing_object("user", self.driver, self.logger, self.configInfo) def open_SignUp_popup(self): self.base.beginOfTest_logFormat("open_SignUp_popup") @@ -22,8 +24,7 @@ class Test_SignUp(BaseTest, unittest.TestCase): canOpen_popUp = True self.logger.info("Success. Can open the register popup.") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Cannot open the Register pop up", e, - self.configError["cannot_open_register_popup"], "Home") + error_handler("error", self.logger, "", "Failure. Cannot open the Register pop up", e, "", "") return canOpen_popUp def signUp_fail_lackOneField(self): @@ -40,8 +41,7 @@ class Test_SignUp(BaseTest, unittest.TestCase): assert (message == expected_message) self.logger.info("Success. Tested the case of not entered the email field.") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Empty email field but can still registered. Broken implementation", e, - self.configError["empty_email_passed"], "Home") + error_handler("error", self.logger, "", "Failure. Empty email field but can still registered. Broken implementation", e, "", "") def signUp_fail_existingEmail(self): self.base.beginOfTest_logFormat("signUp_fail_existingEmail") @@ -54,8 +54,7 @@ class Test_SignUp(BaseTest, unittest.TestCase): assert (message == "Email already taken") self.logger.info("Success. Tested the case of using existing email.") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Existing email was used to sign up the account. Broken implementation", e, - self.configError["existing_email_passed"], "Home") + error_handler("error", self.logger, "", "Failure. Existing email was used to sign up the account. Broken implementation", e, "", "") def signUp_fail_confirmPassword(self): self.base.beginOfTest_logFormat("signUp_fail_confirmPassword") @@ -70,8 +69,7 @@ class Test_SignUp(BaseTest, unittest.TestCase): assert (message == expected_message) self.logger.info("Success. Tested the case of different entered password and confirmed password.") except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Confirm password was different from entered password. Broken implementation", e, - self.configError["incorrect_confirm_password"], "Home") + error_handler("error", self.logger, "", "Failure. Confirm password was different from entered password. Broken implementation", e, "", "") def signUp_success(self): self.base.beginOfTest_logFormat("signUp_success") @@ -81,23 +79,15 @@ class Test_SignUp(BaseTest, unittest.TestCase): self.driver.find_element(By.XPATH, "//input[@name='confirmPassword']").clear() enter_password(self.driver, self.logger, self.configInfo, "valid", "re_enter") click_register(self.driver, self.logger) - wait = WebDriverWait(self.driver, 2) + wait = WebDriverWait(self.driver, 4) wait.until(expected_conditions.visibility_of_element_located((By.TAG_NAME, "picture"))) user_icon = self.driver.find_element(By.TAG_NAME, "picture") assert (user_icon.is_displayed()) self.logger.debug("Saw the user icon") self.logger.info("Success. Tested registering a new account.") - - # Delete the testing account - testUser_id = get_user_info(self.configInfo, "id", "signUp") - admin_token = get_user_info(self.configInfo, "token", "admin") - delete_user(admin_token, testUser_id) - self.logger.debug("Deleting the testing user.") - except Exception as e: - error_handler(self.logger, self.configInfo, "Failure. Cannot register a new account.", e, - self.configError["cannot_register_account"], "Home") - + error_handler("error", self.logger, "", "Failure. Cannot register a new account.", e, "", "") + self.driver.get_screenshot_as_file("screenshot-failed-register.png") # Test case 5: Enter all info but invalid email address, catch the message -> this is failing diff --git a/util.py b/util.py index f80d3df62a44652adc3a2b3d1635fde92463b4f8..1be30ee34d5019e879c02a713af7d4ed329c0fae 100644 --- a/util.py +++ b/util.py @@ -1,4 +1,5 @@ from selenium.webdriver.common.by import By +from selenium.webdriver.support.select import Select from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions from selenium.common.exceptions import NoSuchElementException @@ -11,4 +12,5 @@ import json import requests import time import os +import re from actions import * \ No newline at end of file