From c3036e2bf4eae39c7c5a424f445c815770aa2151 Mon Sep 17 00:00:00 2001 From: test Date: Mon, 7 Oct 2024 10:18:29 +0600 Subject: [PATCH 01/14] [Fix] selenium_driver variable added in v2 --- Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py index 88d07591d..a8eb9dd0e 100644 --- a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py +++ b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py @@ -1251,7 +1251,7 @@ def Go_To_Link_V2(step_data): selenium_driver.get(url) selenium_driver.maximize_window() - + Shared_Resources.Set_Shared_Variables("selenium_driver", selenium_driver) CommonUtil.set_screenshot_vars(Shared_Resources.Shared_Variable_Export()) return "passed" From 3db54bbb27e92777a5d65c5a4a142e6a44d5c6ee Mon Sep 17 00:00:00 2001 From: Muntasib-creator Date: Tue, 8 Oct 2024 13:15:40 +0600 Subject: [PATCH 02/14] [Add] extension support in v2 --- .../Web/Selenium/BuiltInFunctions.py | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py index a8eb9dd0e..375577107 100644 --- a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py +++ b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py @@ -1197,24 +1197,29 @@ def Go_To_Link_V2(step_data): page_load_strategy = "normal" for left, _, right in step_data: - if "add argument" in left.lower(): + left = left.strip().lower() + if "add argument" == left: options.add_argument(right.strip()) CommonUtil.ExecLog(sModuleInfo, "Added argument: " + right.strip(), 1) - elif 'add experimental option' in left.lower(): + elif "add extension" == left: + filepath = CommonUtil.path_parser(right.strip()) + options.add_extension(filepath) + CommonUtil.ExecLog(sModuleInfo, "Added extension: " + filepath, 1) + elif 'add experimental option' in left: options.add_experimental_option(eval(right.split(",",1)[0].strip()),eval(right.split(",",1)[1].strip())) CommonUtil.ExecLog(sModuleInfo, "Added experimental option: " + right.strip(), 1) - elif "set capability" in left.lower(): + elif "set capability" in left: options.set_capability(eval(right.split(",",1)[0].strip()),eval(right.split(",",1)[1].strip())) CommonUtil.ExecLog(sModuleInfo, "Added capability: " + right.strip(), 1) - elif "go to link v2" in left.lower(): + elif "go to link v2" == left: url = right.strip() if right.strip() != "" else None - elif "driver tag" in left.lower(): + elif "driver tag" == left: driver_tag = right.strip() - elif "wait for element" in left.lower(): + elif "wait for element" == left: Shared_Resources.Set_Shared_Variables("element_wait", float(right.strip())) - elif "page load timeout" in left.lower(): + elif "page load timeout" == left: page_load_timeout_sec = float(right.strip()) - elif "page load strategy" in left.lower(): + elif "page load strategy" == left: page_load_strategy = right.strip() options.page_load_strategy = page_load_strategy From 3de90b9b22a16e55b907e3c5684957bbc3708b7b Mon Sep 17 00:00:00 2001 From: Muntasib-creator Date: Tue, 8 Oct 2024 13:16:26 +0600 Subject: [PATCH 03/14] Remove useAutomationExtension arg --- Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py index 375577107..fa6094844 100644 --- a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py +++ b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py @@ -713,8 +713,6 @@ def Open_Browser(dependency, window_size_X=None, window_size_Y=None, capability= if browser == "android": mobile_emulation = {"deviceName": "Pixel 2 XL"} options.add_experimental_option("mobileEmulation", mobile_emulation) - else: - options.add_experimental_option("useAutomationExtension", False) # On Debug run open inspector with credentials if CommonUtil.debug_status and ConfigModule.get_config_value("Inspector", "ai_plugin").strip().lower() in ("true", "on", "enable", "yes", "on_debug"): From 1e534208b195f9a0e38b4d08d80e70204c7aba20 Mon Sep 17 00:00:00 2001 From: Muntasib-creator Date: Wed, 9 Oct 2024 02:55:32 +0600 Subject: [PATCH 04/14] refactor --- .../Web/Selenium/BuiltInFunctions.py | 150 ++++++++---------- 1 file changed, 69 insertions(+), 81 deletions(-) diff --git a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py index fa6094844..960973842 100644 --- a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py +++ b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py @@ -503,72 +503,70 @@ def browser_process_status(browser:str): @logger def Open_Browser(dependency, window_size_X=None, window_size_Y=None, capability=None, browser_options=None, profile_options=None): """ Launch browser and create instance """ - - global selenium_driver - sModuleInfo = inspect.currentframe().f_code.co_name + " : " + MODULE_NAME - try: - browser = dependency["Browser"] - except Exception: - ErrorMessage = ( - "Dependency not set for browser. Please set the Apply Filter value to YES." - ) - return CommonUtil.Exception_Handler(sys.exc_info(), None, ErrorMessage) - - remote_host = None - remote_browser_version = None - - if browser_options is None: - browser_options = [] - for i in range(len(browser_options)): - if '--user-data-dir' in browser_options[i][1]: - custom_profile_folder_path = os.path.abspath(os.path.join(os.getcwd(), os.pardir,'custom_profiles')) - custom_profile_path = os.path.join(custom_profile_folder_path,browser_options[i][1].split('=')[-1].strip()) + global selenium_driver + sModuleInfo = inspect.currentframe().f_code.co_name + " : " + MODULE_NAME + try: + browser = dependency["Browser"] + except Exception: + ErrorMessage = ( + "Dependency not set for browser. Please set the Apply Filter value to YES." + ) + return CommonUtil.Exception_Handler(sys.exc_info(), None, ErrorMessage) - os.makedirs(custom_profile_folder_path, exist_ok=True) - browser_options[i][1] = f'--user-data-dir={custom_profile_path}' - - if Shared_Resources.Test_Shared_Variables('run_time_params'): # Look for remote config in runtime params - run_time_params = Shared_Resources.Get_Shared_Variables('run_time_params') - remote_config = run_time_params.get("remote_config") - if(remote_config): - remote_host = remote_config.get('host') - remote_browser_version = remote_config.get('browser_version') - if(remote_host): - try: - if requests.get(remote_host).status_code != 200: + remote_host = None + remote_browser_version = None + + if browser_options is None: + browser_options = [] + for i in range(len(browser_options)): + if '--user-data-dir' in browser_options[i][1]: + custom_profile_folder_path = os.path.abspath(os.path.join(os.getcwd(), os.pardir,'custom_profiles')) + custom_profile_path = os.path.join(custom_profile_folder_path,browser_options[i][1].split('=')[-1].strip()) + + os.makedirs(custom_profile_folder_path, exist_ok=True) + browser_options[i][1] = f'--user-data-dir={custom_profile_path}' + + if Shared_Resources.Test_Shared_Variables('run_time_params'): # Look for remote config in runtime params + run_time_params = Shared_Resources.Get_Shared_Variables('run_time_params') + remote_config = run_time_params.get("remote_config") + if(remote_config): + remote_host = remote_config.get('host') + remote_browser_version = remote_config.get('browser_version') + if(remote_host): + try: + if requests.get(remote_host).status_code != 200: + remote_host = None + except requests.exceptions.RequestException as e: remote_host = None - except requests.exceptions.RequestException as e: - remote_host = None - if remote_host == None: - CommonUtil.ExecLog( - sModuleInfo, "Remote host: %s is not up. Running the browser locally " % remote_config.get('host'), 3 - ) - - is_browserstack = 'browserstack' in browser - if is_browserstack: - try: - browerstack_config = json.loads(browser) - browser = 'browserstack' - remote_host = browerstack_config['remote_host'] - desired_cap = browerstack_config['desired_cap'] - remote_desired_cap = { - 'bstack:options' : { - "os" : desired_cap["os"], - "osVersion" : desired_cap['os_version'], - "browserVersion" : desired_cap['browser_version'], - "local" : "false", - "seleniumVersion" : "4.8.0", - }, - "browserName" : desired_cap['browser'], - } - except ValueError as e: - is_browserstack = False - CommonUtil.ExecLog( - sModuleInfo, "Unable to parse browserstack config. Running the browser locally", 3 - ) + if remote_host == None: + CommonUtil.ExecLog( + sModuleInfo, "Remote host: %s is not up. Running the browser locally " % remote_config.get('host'), 3 + ) + + is_browserstack = 'browserstack' in browser + if is_browserstack: + try: + browerstack_config = json.loads(browser) + browser = 'browserstack' + remote_host = browerstack_config['remote_host'] + desired_cap = browerstack_config['desired_cap'] + remote_desired_cap = { + 'bstack:options' : { + "os" : desired_cap["os"], + "osVersion" : desired_cap['os_version'], + "browserVersion" : desired_cap['browser_version'], + "local" : "false", + "seleniumVersion" : "4.8.0", + }, + "browserName" : desired_cap['browser'], + } + except ValueError as e: + is_browserstack = False + CommonUtil.ExecLog( + sModuleInfo, "Unable to parse browserstack config. Running the browser locally", 3 + ) - try: CommonUtil.teardown = True browser = browser.lower().strip() import selenium @@ -634,11 +632,6 @@ def Open_Browser(dependency, window_size_X=None, window_size_Y=None, capability= "platformName": "Android", "automationName": "UIAutomator2", "browserName": "Chrome" - - # Platform specific details may later be fetched from the device - # list sent by zeuz server. - # "platformVersion": "9.0", - # "deviceName": "Android Emulator", } elif browser == "ios": capabilities = { @@ -672,10 +665,15 @@ def Open_Browser(dependency, window_size_X=None, window_size_Y=None, capability= # capability if capability: for key, value in capability.items(): - # options.set_capability('unhandledPromptBehavior', 'ignore') options.set_capability(key, value) + options.set_capability("goog:loggingPrefs", {"performance": "ALL"}) + + # arguments + # On Debug run open inspector with credentials + if CommonUtil.debug_status and ConfigModule.get_config_value("Inspector", "ai_plugin").strip().lower() in ("true", "on", "enable", "yes", "on_debug"): + set_extension_variables() + options.add_argument(f"load-extension={aiplugin_path},{ai_recorder_path}") - # argument if not browser_options: # options.add_argument("--no-sandbox") # options.add_argument("--disable-extensions") @@ -714,11 +712,6 @@ def Open_Browser(dependency, window_size_X=None, window_size_Y=None, capability= mobile_emulation = {"deviceName": "Pixel 2 XL"} options.add_experimental_option("mobileEmulation", mobile_emulation) - # On Debug run open inspector with credentials - if CommonUtil.debug_status and ConfigModule.get_config_value("Inspector", "ai_plugin").strip().lower() in ("true", "on", "enable", "yes", "on_debug"): - set_extension_variables() - options.add_argument(f"load-extension={aiplugin_path},{ai_recorder_path}") - if "chromeheadless" in browser: def chromeheadless(): options.add_argument( @@ -738,8 +731,6 @@ def chromeheadless(): for key in _prefs: prefs[key] = _prefs[key] options.add_experimental_option('prefs', prefs) - - options.set_capability("goog:loggingPrefs", {"performance": "ALL"}) if remote_host: selenium_driver = webdriver.Remote( @@ -754,7 +745,6 @@ def chromeheadless(): options=options, ) - selenium_driver.implicitly_wait(WebDriver_Wait) if not window_size_X and not window_size_Y: selenium_driver.maximize_window() @@ -1284,8 +1274,6 @@ def Go_To_Link(step_data, page_title=False): raise ValueError("No dependency set - Cannot run") page_load_timeout_sec = 120 - page_load_strategy = "normal" - try: driver_id = "" for left, mid, right in step_data: @@ -1294,7 +1282,7 @@ def Go_To_Link(step_data, page_title=False): web_link = right.strip() elif left == "driverid": driver_id = right.strip() - elif left == "waittimetoappearelement": + elif left in ("waittimetoappearelement", "waitforelement"): Shared_Resources.Set_Shared_Variables("element_wait", float(right.strip())) elif left == "waittimetopageload": page_load_timeout_sec = int(right.strip()) @@ -3044,7 +3032,7 @@ def Tear_Down_Selenium(step_data=[]): if not driver_id: if not CommonUtil.teardown: - CommonUtil.ExecLog(sModuleInfo, "Browser is already closed", 1) + CommonUtil.ExecLog(sModuleInfo, "Browser is already closed", 2) CommonUtil.Join_Thread_and_Return_Result("screenshot") # Let the capturing screenshot end in thread for driver in selenium_details: try: From f02fb774e464b615e8e0d2740255c23b74c724a6 Mon Sep 17 00:00:00 2001 From: Muntasib-creator Date: Wed, 9 Oct 2024 02:59:50 +0600 Subject: [PATCH 05/14] refactor --- .../Built_In_Automation/Web/Selenium/BuiltInFunctions.py | 6 ------ Framework/Utilities/CommonUtil.py | 3 ++- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py index 960973842..f36a9b99d 100644 --- a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py +++ b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py @@ -384,7 +384,6 @@ def Open_Electron_App(data_set): selenium_driver.implicitly_wait(WebDriver_Wait) CommonUtil.ExecLog(sModuleInfo, "Started Electron App", 1) Shared_Resources.Set_Shared_Variables("selenium_driver", selenium_driver) - CommonUtil.teardown = True CommonUtil.set_screenshot_vars(Shared_Resources.Shared_Variable_Export()) except: CommonUtil.ExecLog(sModuleInfo, "To start an Electron app, you need to download a ChromeDriver with the version that your Electron app supports.\n" + @@ -567,7 +566,6 @@ def Open_Browser(dependency, window_size_X=None, window_size_Y=None, capability= sModuleInfo, "Unable to parse browserstack config. Running the browser locally", 3 ) - CommonUtil.teardown = True browser = browser.lower().strip() import selenium selenium_version = selenium.__version__ @@ -1063,7 +1061,6 @@ def edgeheadless(): return CommonUtil.Exception_Handler(sys.exc_info()) except Exception: - CommonUtil.teardown = False return CommonUtil.Exception_Handler(sys.exc_info()) @@ -3031,8 +3028,6 @@ def Tear_Down_Selenium(step_data=[]): driver_id = right.strip() if not driver_id: - if not CommonUtil.teardown: - CommonUtil.ExecLog(sModuleInfo, "Browser is already closed", 2) CommonUtil.Join_Thread_and_Return_Result("screenshot") # Let the capturing screenshot end in thread for driver in selenium_details: try: @@ -3063,7 +3058,6 @@ def Tear_Down_Selenium(step_data=[]): Shared_Resources.Remove_From_Shared_Variables("selenium_driver") selenium_details = {} selenium_driver = None - CommonUtil.teardown = False elif driver_id not in selenium_details: CommonUtil.ExecLog(sModuleInfo, "Driver_id='%s' not found. So could not tear down" % driver_id, 2) diff --git a/Framework/Utilities/CommonUtil.py b/Framework/Utilities/CommonUtil.py index 3e8af15b4..b6b111aef 100644 --- a/Framework/Utilities/CommonUtil.py +++ b/Framework/Utilities/CommonUtil.py @@ -123,7 +123,8 @@ upload_on_fail = True rerun_on_fail = True passed_after_rerun = False -Affirmative_words = ("yes", "true", "ok", "enable", "on") +Affirmative_words = ("yes", "true", "on", "ok", "accept", "enable") +negative_words = ("no", "false", "off", "dismiss", "decline", "disable") runid_index = 0 tc_index = 0 From 0152d5e7849c1de2cfeea5a3342374b126152ec3 Mon Sep 17 00:00:00 2001 From: Muntasib-creator Date: Thu, 10 Oct 2024 04:27:18 +0600 Subject: [PATCH 06/14] Chrome and Edge refactor v1 --- .../Desktop/Windows/BuiltInFunctions.py | 6 +- .../action_declarations/selenium.py | 2 - .../Web/Selenium/BuiltInFunctions.py | 893 ++++-------------- Framework/Utilities/CommonUtil.py | 5 +- 4 files changed, 203 insertions(+), 703 deletions(-) diff --git a/Framework/Built_In_Automation/Desktop/Windows/BuiltInFunctions.py b/Framework/Built_In_Automation/Desktop/Windows/BuiltInFunctions.py index 619bd968f..0983037f0 100644 --- a/Framework/Built_In_Automation/Desktop/Windows/BuiltInFunctions.py +++ b/Framework/Built_In_Automation/Desktop/Windows/BuiltInFunctions.py @@ -851,7 +851,7 @@ def _child_search_by_path( if found: if switch_window: CommonUtil.ExecLog(sModuleInfo, "Switching to window: %s" % NameE, 1) - if Shared_Resources.Get_Shared_Variables("zeuz_window_auto_switch").strip().lower() in CommonUtil.Affirmative_words: + if Shared_Resources.Get_Shared_Variables("zeuz_window_auto_switch").strip().lower() in CommonUtil.affirmative_words: autoit.win_activate(NameE) all_elements.append(each_child) if 0 <= element_index == len(all_elements) - 1: break @@ -1653,7 +1653,7 @@ def _get_main_window(WindowName): if MainWindowElement.Current.ProcessId in current_pid_list: CommonUtil.ExecLog(sModuleInfo, "Switching to window: %s" % NameS, 1) CommonUtil.ExecLog(sModuleInfo, f"pid matched: {MainWindowElement.Current.ProcessId}", 5) - if Shared_Resources.Get_Shared_Variables("zeuz_window_auto_switch").strip().lower() in CommonUtil.Affirmative_words: + if Shared_Resources.Get_Shared_Variables("zeuz_window_auto_switch").strip().lower() in CommonUtil.affirmative_words: autoit.win_activate(NameS) return MainWindowElement else: @@ -1662,7 +1662,7 @@ def _get_main_window(WindowName): pass if len(found_windows) > 0: CommonUtil.ExecLog(sModuleInfo, "Switching to window: %s" % found_windows[0].Current.Name, 1) - if Shared_Resources.Get_Shared_Variables("zeuz_window_auto_switch").strip().lower() in CommonUtil.Affirmative_words: + if Shared_Resources.Get_Shared_Variables("zeuz_window_auto_switch").strip().lower() in CommonUtil.affirmative_words: autoit.win_activate(found_windows[0].Current.Name) return found_windows[0] return None diff --git a/Framework/Built_In_Automation/Sequential_Actions/action_declarations/selenium.py b/Framework/Built_In_Automation/Sequential_Actions/action_declarations/selenium.py index 7c63322da..56c210c5e 100644 --- a/Framework/Built_In_Automation/Sequential_Actions/action_declarations/selenium.py +++ b/Framework/Built_In_Automation/Sequential_Actions/action_declarations/selenium.py @@ -27,7 +27,6 @@ { "name": "navigate", "function": "Navigate", "screenshot": "web" }, { "name": "validate table", "function": "validate_table", "screenshot": "web" }, { "name": "handle alert", "function": "Handle_Browser_Alert", "screenshot": "desktop"}, - { "name": "browser", "function": "Open_Browser_Wrapper", "screenshot": "web" }, { "name": "teardown", "function": "Tear_Down_Selenium", "screenshot": "none"}, { "name": "open new tab", "function": "open_new_tab", "screenshot": "web" }, { "name": "close tab", "function": "close_tab", "screenshot": "web" }, @@ -56,7 +55,6 @@ { "name": "check uncheck", "function": "check_uncheck", "screenshot": "web" }, { "name": "multiple check uncheck", "function": "multiple_check_uncheck", "screenshot": "web" }, { "name": "slider bar", "function": "slider_bar", "screenshot": "web" }, - { "name": "get performance metrics", "function": "get_performance_metrics", "screenshot": "web" }, { "name": "resize window", "function": "resize_window", "screenshot": "web" }, { "name": "change attribute value", "function": "Change_Attribute_Value", "screenshot": "web" }, { "name": "capture network log", "function": "capture_network_log", "screenshot": "web" }, diff --git a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py index f36a9b99d..8509aa00f 100644 --- a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py +++ b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py @@ -83,14 +83,41 @@ # Disable WebdriverManager SSL verification. os.environ['WDM_SSL_VERIFY'] = '0' -WebDriver_Wait = 1 -WebDriver_Wait_Short = 1 - current_driver_id = None selenium_driver = None selenium_details = {} default_x, default_y = 1920, 1080 vdisplay = None +initial_download_folder = None + +browser_map = { + "Microsoft Edge Chromium": 'msedge', + "Chrome": "chrome", + "FireFox": "firefox", + "Opera": "opera", + "ChromeHeadless": "chrome", + "FirefoxHeadless": "firefox", + "EdgeChromiumHeadless": "msedge", +} + +from typing import Literal, TypedDict, Any, Union, NotRequired +Dataset = list[tuple[str, str, str]] +ReturnType = Literal["passed", "zeuz_failed"] + +class DefaultChromiumArguments(TypedDict): + add_argument: list[str] + add_experimental_option: dict[str, dict[str, Any]] + add_extension: list[str] + add_encoded_extension: list[str] + page_load_strategy: NotRequired[Literal["normal", "eager", "none"]] + +class BrowserOptions(TypedDict): + capabilities: dict[str,Any] + chrome: DefaultChromiumArguments + msedge: DefaultChromiumArguments + firefox: Any + +from selenium.webdriver.common.options import ArgOptions # JavaScript for collecting First Contentful Paint value. JS_FCP = ''' @@ -277,11 +304,9 @@ def is_port_in_use(port): ) env = {"PATH": str(appium_binary_path)} appium_server = subprocess.Popen( - subprocess.Popen( - "%s --allow-insecure chromedriver_autodownload -p %s" - % (appium_binary, str(appium_port)), - shell=True, - ), + "%s --allow-insecure chromedriver_autodownload -p %s" + % (appium_binary, str(appium_port)), + shell=True, env=env, ) except: @@ -364,32 +389,15 @@ def Open_Electron_App(data_set): try: from selenium.webdriver.chrome.options import Options + from selenium.webdriver.chrome.service import Service opts = Options() opts.binary_location = desktop_app_path - selenium_driver = webdriver.Chrome(executable_path=electron_chrome_path, chrome_options=opts) - selenium_driver.implicitly_wait(WebDriver_Wait) + selenium_driver = webdriver.Chrome(opts, Service()) + selenium_driver.implicitly_wait(0.5) CommonUtil.ExecLog(sModuleInfo, "Started Electron App", 1) Shared_Resources.Set_Shared_Variables("selenium_driver", selenium_driver) CommonUtil.set_screenshot_vars(Shared_Resources.Shared_Variable_Export()) - except SessionNotCreatedException as exc: - try: - major_version = exc.msg.split("\n")[1].split("is ", 1)[1].split(".")[0] - specific_version = requests.get("https://chromedriver.storage.googleapis.com/LATEST_RELEASE_" + major_version).text - electron_chrome_path = ChromeDriverManager(version=specific_version).install() - ConfigModule.add_config_value("Selenium_driver_paths", "electron_chrome_path", electron_chrome_path) - from selenium.webdriver.chrome.options import Options - opts = Options() - opts.binary_location = desktop_app_path - selenium_driver = webdriver.Chrome(executable_path=electron_chrome_path, chrome_options=opts) - selenium_driver.implicitly_wait(WebDriver_Wait) - CommonUtil.ExecLog(sModuleInfo, "Started Electron App", 1) - Shared_Resources.Set_Shared_Variables("selenium_driver", selenium_driver) - CommonUtil.set_screenshot_vars(Shared_Resources.Shared_Variable_Export()) - except: - CommonUtil.ExecLog(sModuleInfo, "To start an Electron app, you need to download a ChromeDriver with the version that your Electron app supports.\n" + - "Visit this link to download specific version of Chrome driver: https://chromedriver.chromium.org/downloads\n" + - 'Then add the path of the ChromeDriver path into Framework/settings.conf file "Selenium_driver_paths" section with "electron_chrome_path" name', 3) - return "zeuz_failed" + except Exception: return CommonUtil.Exception_Handler(sys.exc_info()) @@ -402,34 +410,6 @@ def Open_Electron_App(data_set): except: return CommonUtil.Exception_Handler(sys.exc_info()) - -@logger -def get_performance_metrics(dataset): - try: - label = driver_id = "" - for left, mid, right in dataset: - left = left.replace(" ", "").replace("_", "").replace("-", "").lower() - if left == "driverid": - driver_id = right.strip() - elif left == "getperformancemetrics": - var_name = right.strip() - elif left == "label": - label = right.strip() - - if not driver_id: - driver_id = current_driver_id - - # from selenium.webdriver.common.devtools.v101.performance import enable, disable, get_metrics - # from selenium.webdriver.chrome.webdriver import ChromiumDriver - # time.sleep(5) - - perf_json_data = collect_browser_metrics(driver_id, label if label else CommonUtil.previous_action_name) - Shared_Resources.Set_Shared_Variables(var_name, perf_json_data) - return "passed" - except: - return CommonUtil.Exception_Handler(sys.exc_info()) - - @logger def use_xvfb_or_headless(callback): sModuleInfo = inspect.currentframe().f_code.co_name + " : " + MODULE_NAME @@ -484,232 +464,76 @@ def set_extension_variables(): return CommonUtil.Exception_Handler(sys.exc_info(), None, "Could not load recorder extension") -def browser_process_status(browser:str): - list_process_command = ['tasklist'] - seacrh_command = ['findstr', f'{browser}.exe'] - - list_process = subprocess.Popen(list_process_command, stdout=subprocess.PIPE) - search_process = subprocess.Popen(seacrh_command, stdin=list_process.stdout, stdout=subprocess.PIPE, text=True) - - output,_ = search_process.communicate() - - if output: - return True - else: - return False +def generate_options(browser: str, browser_options:BrowserOptions): + """ Adds capabilities and options for Browser/WebDriver """ + if browser in ("android", "chrome", "chromeheadless", "microsoft edge chromium", "edgechromiumheadless"): + b = "msedge" if "edge" in browser else "chrome" + from selenium.webdriver.chrome.options import Options as ChromeOptions + from selenium.webdriver.edge.options import Options as EdgeOptions + options = ChromeOptions() if b == "chrome" else EdgeOptions() + if browser == "android": + mobile_emulation = {"deviceName": "Pixel 2 XL"} + options.add_experimental_option("mobileEmulation", mobile_emulation) + for argument in browser_options[b]["add_argument"]: + options.add_argument(argument) + for argument in browser_options[b]["add_extension"]: + options.add_extension(argument) + for argument in browser_options[b]["add_encoded_extension"]: + options.add_encoded_extension(argument) + if "page_load_strategy" in browser_options[b]: + options.page_load_strategy = browser_options[b]["page_load_strategy"] + + if "headless" in browser: + def chromeheadless(): + options.add_argument( + "--headless=new" + ) + use_xvfb_or_headless(chromeheadless) + + for key, value in browser_options["capabilities"].items(): + options.set_capability(key, value) + + # On Debug run open inspector with credentials + if ( + CommonUtil.debug_status and + ConfigModule.get_config_value("Inspector", "ai_plugin").strip().lower() in ("true", "on", "enable", "yes", "on_debug") and + browser in ("chrome", "microsoft edge chromium") + ): + set_extension_variables() + options.add_argument(f"load-extension={aiplugin_path},{ai_recorder_path}") + # This is for running extension on a http server to call a https request + options.add_argument("--allow-running-insecure-content") + return options -initial_download_folder = None @logger -def Open_Browser(dependency, window_size_X=None, window_size_Y=None, capability=None, browser_options=None, profile_options=None): +def Open_Browser(browser, browser_options: BrowserOptions): """ Launch browser and create instance """ try: global selenium_driver sModuleInfo = inspect.currentframe().f_code.co_name + " : " + MODULE_NAME - try: - browser = dependency["Browser"] - except Exception: - ErrorMessage = ( - "Dependency not set for browser. Please set the Apply Filter value to YES." - ) - return CommonUtil.Exception_Handler(sys.exc_info(), None, ErrorMessage) - - remote_host = None - remote_browser_version = None - - if browser_options is None: - browser_options = [] - for i in range(len(browser_options)): - if '--user-data-dir' in browser_options[i][1]: - custom_profile_folder_path = os.path.abspath(os.path.join(os.getcwd(), os.pardir,'custom_profiles')) - custom_profile_path = os.path.join(custom_profile_folder_path,browser_options[i][1].split('=')[-1].strip()) - - os.makedirs(custom_profile_folder_path, exist_ok=True) - browser_options[i][1] = f'--user-data-dir={custom_profile_path}' - - if Shared_Resources.Test_Shared_Variables('run_time_params'): # Look for remote config in runtime params - run_time_params = Shared_Resources.Get_Shared_Variables('run_time_params') - remote_config = run_time_params.get("remote_config") - if(remote_config): - remote_host = remote_config.get('host') - remote_browser_version = remote_config.get('browser_version') - if(remote_host): - try: - if requests.get(remote_host).status_code != 200: - remote_host = None - except requests.exceptions.RequestException as e: - remote_host = None - if remote_host == None: - CommonUtil.ExecLog( - sModuleInfo, "Remote host: %s is not up. Running the browser locally " % remote_config.get('host'), 3 - ) - - is_browserstack = 'browserstack' in browser - if is_browserstack: - try: - browerstack_config = json.loads(browser) - browser = 'browserstack' - remote_host = browerstack_config['remote_host'] - desired_cap = browerstack_config['desired_cap'] - remote_desired_cap = { - 'bstack:options' : { - "os" : desired_cap["os"], - "osVersion" : desired_cap['os_version'], - "browserVersion" : desired_cap['browser_version'], - "local" : "false", - "seleniumVersion" : "4.8.0", - }, - "browserName" : desired_cap['browser'], - } - except ValueError as e: - is_browserstack = False - CommonUtil.ExecLog( - sModuleInfo, "Unable to parse browserstack config. Running the browser locally", 3 - ) - - browser = browser.lower().strip() - import selenium - selenium_version = selenium.__version__ - - kill_process = False - - browser_map = { - "microsoft edge chromium": 'msedge', - "chrome": "chrome", - "firefox": "firefox", - "chromeheadless": "chrome", - "firefoxheadless": "firefox", - "edgechromiumheadless": "msedge", - } - - if profile_options: - if browser.strip().lower() in browser_map.keys(): - browser_short_form = browser_map[browser] - process_status = browser_process_status(browser_short_form) - for options in profile_options: - if options[0] == "autokillforprofile" and options[1] == "True": - kill_process = True - - if process_status == True and kill_process == False: - err_msg = f''' - Please close all the {browser} browser instance. - Or, use the following optional parameter to do it automatically: - ( auto kill for profile | browser option | True ) - ''' - CommonUtil.ExecLog( - sModuleInfo, err_msg, 3 - ) - raise Exception - elif process_status == True and kill_process == True: - task_kill_command = ['taskkill', '/IM', f'{browser_short_form}.exe', '/F'] - task_kill_process = subprocess.Popen(task_kill_command, stdout=subprocess.PIPE, text=True) - kill_output,err = task_kill_process.communicate() - kill_output_status = kill_output.split()[0] - if kill_output_status == "SUCCESS:": - CommonUtil.ExecLog( - sModuleInfo, f"Successfully terminated all the {browser_short_form}.exe processes", 1 - ) - else: - CommonUtil.ExecLog( - sModuleInfo, f"Could not terminate the {browser_short_form}.exe processes", 3 - ) - else: - CommonUtil.ExecLog( - sModuleInfo, f"ZeuZ does not support browser profile for {browser} browser", 3 - ) - raise Exception - - if browser in ("ios",): + browser = browser.lower().strip() + if browser == "ios": # Finds the appium binary and starts the server. appium_port = start_appium_server() if appium_port == "zeuz_failed": return "zeuz_failed" - if browser == "android": - capabilities = { - "platformName": "Android", - "automationName": "UIAutomator2", - "browserName": "Chrome" - } - elif browser == "ios": - capabilities = { - "platformName": "iOS", - "automationName": "XCUITest", - "browserName": "Safari" - - # Platform specific details may later be fetched from the device - # list sent by zeuz server. - } + capabilities = { + "platformName": "iOS", + "automationName": "XCUITest", + "browserName": "Safari" + } from appium import webdriver as appiumdriver + from appium.options.android import UiAutomator2Options + capabilities_options = UiAutomator2Options().load_capabilities(capabilities) + selenium_driver = appiumdriver.Remote("http://localhost:%d" % appium_port, options=capabilities_options) + return "passed" - selenium_driver = appiumdriver.Remote("http://localhost:%d" % appium_port, capabilities) - selenium_driver.implicitly_wait(WebDriver_Wait) - - elif browser in ("android", "chrome", "chromeheadless"): - from selenium.webdriver.chrome.options import Options + options = generate_options(browser, browser_options) + if browser in ("android", "chrome", "chromeheadless"): from selenium.webdriver.chrome.service import Service - chrome_path = ConfigModule.get_config_value("Selenium_driver_paths", "chrome_path") - try: - if not chrome_path: - chrome_path = ChromeDriverManager().install() - ConfigModule.add_config_value("Selenium_driver_paths", "chrome_path", chrome_path) - except: - CommonUtil.ExecLog(sModuleInfo, "Unable to download chromedriver using ChromedriverManager", 2) - options = Options() - - if remote_browser_version: - options.set_capability("browserVersion",remote_browser_version) - # capability - if capability: - for key, value in capability.items(): - options.set_capability(key, value) - options.set_capability("goog:loggingPrefs", {"performance": "ALL"}) - - # arguments - # On Debug run open inspector with credentials - if CommonUtil.debug_status and ConfigModule.get_config_value("Inspector", "ai_plugin").strip().lower() in ("true", "on", "enable", "yes", "on_debug"): - set_extension_variables() - options.add_argument(f"load-extension={aiplugin_path},{ai_recorder_path}") - - if not browser_options: - # options.add_argument("--no-sandbox") - # options.add_argument("--disable-extensions") - options.add_argument('--ignore-certificate-errors') - options.add_argument('--ignore-ssl-errors') - options.add_argument('--zeuz_pid_finder') - options.add_argument('--allow-running-insecure-content') # This is for running extension on a http server to call a https request - - # Turn this on while experimenting with playwright - # options.add_argument('--remote-debugging-port=9222') - - # Todo: profile, add_argument => open_browser - _prefs = {} - if browser_options: - for left, right in browser_options: - if left in ("addargument", "addarguments"): - options.add_argument(right.strip()) - print(left, right) - if "pageloadstrategy" in left: - options.page_load_strategy = right.strip() - elif left in ("addextension", "addextensions"): - options.add_extension(CommonUtil.path_parser(right.strip())) - elif left in ("addexperimentaloption"): - if "prefs" in right: - _prefs = right["prefs"] - else: - options.add_experimental_option(list(right.items())[0][0], list(right.items())[0][1]) - - if profile_options: - for left, right in profile_options: - if left in ("addargument", "addarguments"): - options.add_argument(right.strip()) - print(left, right) - - if browser == "android": - mobile_emulation = {"deviceName": "Pixel 2 XL"} - options.add_experimental_option("mobileEmulation", mobile_emulation) - if "chromeheadless" in browser: def chromeheadless(): options.add_argument( @@ -717,45 +541,19 @@ def chromeheadless(): ) use_xvfb_or_headless(chromeheadless) - global initial_download_folder - initial_download_folder = download_dir = ConfigModule.get_config_value("sectionOne", "initial_download_folder", temp_config) - prefs = { - "profile.default_content_settings.popups": 0, - "download.default_directory": download_dir, - "download.prompt_for_download": False, - "download.directory_upgrade": True, - 'safebrowsing.enabled': 'false' - } - for key in _prefs: - prefs[key] = _prefs[key] - options.add_experimental_option('prefs', prefs) - - if remote_host: - selenium_driver = webdriver.Remote( - command_executor= remote_host + "wd/hub", - options=options, - ) - else: - import selenium - service = Service() - selenium_driver = webdriver.Chrome( - service=service, - options=options, - ) + service = Service() + selenium_driver = webdriver.Chrome( + service=service, + options=options, + ) - selenium_driver.implicitly_wait(WebDriver_Wait) - if not window_size_X and not window_size_Y: - selenium_driver.maximize_window() - else: - if not window_size_X: - window_size_X = 1000 - if not window_size_Y: - window_size_Y = 1000 - selenium_driver.set_window_size(window_size_X, window_size_Y) - CommonUtil.ExecLog(sModuleInfo, "Started Chrome Browser", 1) - Shared_Resources.Set_Shared_Variables("selenium_driver", selenium_driver) - CommonUtil.set_screenshot_vars(Shared_Resources.Shared_Variable_Export()) - return "passed" + elif browser in ("microsoft edge chromium", "edgechromiumheadless"): + from selenium.webdriver.edge.service import Service + service = Service() + selenium_driver = webdriver.Edge( + service=service, + options=options, + ) elif browser in ("firefox", "firefoxheadless"): firefox_path = ConfigModule.get_config_value("Selenium_driver_paths", "firefox_path") @@ -781,7 +579,7 @@ def chromeheadless(): #firefox headless mode needs add_argument options.add_argument("-headless") # options.headless = True - + ''' # commenting out as this is not working. Make sure # whoever implemented this it is tested with latest firefox version @@ -824,177 +622,21 @@ def firefoxheadless(): options.set_preference("browser.download.dir", download_dir) options.set_preference("browser.helperApps.neverAsk.saveToDisk", apps) options.accept_untrusted_certs = True - - if(remote_host): + + if remote_host: capabilities = webdriver.DesiredCapabilities().FIREFOX capabilities['acceptSslCerts'] = True selenium_driver = webdriver.Remote( command_executor= remote_host + "wd/hub", options=options, - desired_capabilities=capabilities, - browser_profile=profile ) else: - if selenium_version.startswith('4.'): - service = Service() - selenium_driver = webdriver.Firefox( - service=service, - options=options, - ) - elif selenium_version.startswith('3.'): - capabilities = webdriver.DesiredCapabilities().FIREFOX - capabilities['acceptSslCerts'] = True - selenium_driver = webdriver.Firefox( - executable_path=firefox_path, - capabilities=capabilities, - options=options, - firefox_profile=profile - ) - else: - print("Please update selenium & rerun node_cli file again.") - - selenium_driver.implicitly_wait(WebDriver_Wait) - if not window_size_X and not window_size_Y: - selenium_driver.maximize_window() - else: - if window_size_X is None: - window_size_X = 1000 - if window_size_Y is None: - window_size_Y = 1000 - selenium_driver.set_window_size(window_size_X, window_size_Y) - CommonUtil.ExecLog(sModuleInfo, "Started Firefox Browser", 1) - Shared_Resources.Set_Shared_Variables("selenium_driver", selenium_driver) - CommonUtil.set_screenshot_vars(Shared_Resources.Shared_Variable_Export()) - return "passed" - - elif browser in ("microsoft edge chromium", "edgechromiumheadless"): - edge_path = ConfigModule.get_config_value("Selenium_driver_paths", "edge_path") - if not edge_path: - edge_path = EdgeChromiumDriverManager().install() - ConfigModule.add_config_value("Selenium_driver_paths", "edge_path", edge_path) - - """We are using a Custom module from Microsoft which inherits Selenium class and provides additional supports which we need. - Since this module inherits Selenium module so all updates will be inherited as well - """ - from Framework.edge_module.msedge.selenium_tools import EdgeOptions, Edge - initial_download_folder = download_dir = ConfigModule.get_config_value("sectionOne", "initial_download_folder", temp_config) - options = webdriver.EdgeOptions() - - if remote_browser_version: - options.set_capability("browserVersion",remote_browser_version) - - options.use_chromium = True - - if profile_options: - for left, right in profile_options: - if left in ("addargument", "addarguments"): - options.add_argument(right.strip()) - print(left, right) - - if "headless" in browser: - def edgeheadless(): - options.headless = True - use_xvfb_or_headless(edgeheadless) - - options.add_experimental_option("prefs", {"download.default_directory": download_dir}) - options.add_argument('--zeuz_pid_finder') - # options.add_argument("--no-sandbox") - # options.add_argument("--disable-extensions") - options.add_argument('--ignore-certificate-errors') - options.add_argument('--ignore-ssl-errors') - options.add_argument('--allow-running-insecure-content') # This is for running extension on a http server to call a https request - if CommonUtil.debug_status and ConfigModule.get_config_value("Inspector", "ai_plugin").strip().lower() in ("true", "on", "enable", "yes", "on_debug"): - set_extension_variables() - options.add_argument(f"load-extension={aiplugin_path},{ai_recorder_path}") - if(remote_host): - capabilities = webdriver.EdgeOptions().capabilities - capabilities['acceptSslCerts'] = True - selenium_driver = webdriver.Remote( - command_executor= remote_host + "wd/hub", + service = Service() + selenium_driver = webdriver.Firefox( + service=service, options=options, - desired_capabilities=capabilities ) - else: - if selenium_version.startswith('4.'): - selenium_driver = webdriver.Edge( - options=options, - ) - elif selenium_version.startswith('3.'): - capabilities = webdriver.EdgeOptions().capabilities - capabilities['acceptSslCerts'] = True - selenium_driver = Edge( - executable_path=edge_path, - options=options, - capabilities=capabilities - ) - else: - print("Please update selenium & rerun node_cli file again.") - - selenium_driver.implicitly_wait(WebDriver_Wait) - if not window_size_X and not window_size_Y: - selenium_driver.maximize_window() - else: - if not window_size_X: - window_size_X = 1000 - if not window_size_Y: - window_size_Y = 1000 - selenium_driver.set_window_size(window_size_X, window_size_Y) - CommonUtil.ExecLog(sModuleInfo, "Started Microsoft Edge Browser", 1) - Shared_Resources.Set_Shared_Variables("selenium_driver", selenium_driver) - CommonUtil.set_screenshot_vars(Shared_Resources.Shared_Variable_Export()) - return "passed" - elif browser == "opera": - opera_path = ConfigModule.get_config_value("Selenium_driver_paths", "opera_path") - if not opera_path: - opera_path = OperaDriverManager().install() - ConfigModule.add_config_value("Selenium_driver_paths", "opera_path", opera_path) - capabilities = webdriver.DesiredCapabilities().OPERA - capabilities['acceptSslCerts'] = True - - from selenium.webdriver.opera.options import Options - options = Options() - options.add_argument("--zeuz_pid_finder") - initial_download_folder = download_dir = ConfigModule.get_config_value("sectionOne", "initial_download_folder", temp_config) - options.add_experimental_option("prefs", {"download.default_directory": download_dir}) # This does not work - # options.binary_location = r'C:\Users\ASUS\AppData\Local\Programs\Opera\launcher.exe' # This might be needed - - selenium_driver = webdriver.Opera(executable_path=opera_path, desired_capabilities=capabilities, options=options) - selenium_driver.implicitly_wait(WebDriver_Wait) - if not window_size_X and not window_size_Y: - selenium_driver.maximize_window() - else: - if not window_size_X: - window_size_X = 1000 - if not window_size_Y: - window_size_Y = 1000 - selenium_driver.set_window_size(window_size_X, window_size_Y) - CommonUtil.ExecLog(sModuleInfo, "Started Opera Browser", 1) - Shared_Resources.Set_Shared_Variables("selenium_driver", selenium_driver) - CommonUtil.set_screenshot_vars(Shared_Resources.Shared_Variable_Export()) - return "passed" - - elif browser == "ie": - ie_path = ConfigModule.get_config_value("Selenium_driver_paths", "ie_path") - if not ie_path: - ie_path = IEDriverManager().install() - ConfigModule.add_config_value("Selenium_driver_paths", "ie_path", ie_path) - capabilities = webdriver.DesiredCapabilities().INTERNETEXPLORER - # capabilities['acceptSslCerts'] = True # It does not work for internet explorer - selenium_driver = webdriver.Ie(executable_path=ie_path, capabilities=capabilities) - selenium_driver.implicitly_wait(WebDriver_Wait) - if not window_size_X and not window_size_Y: - selenium_driver.maximize_window() - else: - if not window_size_X: - window_size_X = 1000 - if not window_size_Y: - window_size_Y = 1000 - selenium_driver.set_window_size(window_size_X, window_size_Y) - CommonUtil.ExecLog(sModuleInfo, "Started Internet Explorer Browser", 1) - Shared_Resources.Set_Shared_Variables("selenium_driver", selenium_driver) - CommonUtil.set_screenshot_vars(Shared_Resources.Shared_Variable_Export()) - return "passed" elif "safari" in browser: CommonUtil.ExecLog(sModuleInfo, "Restart computer after following ... https://developer.apple.com/documentation/webkit/testing_with_webdriver_in_safari ", 1) @@ -1016,80 +658,22 @@ def edgeheadless(): desired_capabilities["safari:useSimulator"] = True selenium_driver = webdriver.Safari(desired_capabilities=desired_capabilities) - selenium_driver.implicitly_wait(WebDriver_Wait) - if not window_size_X and not window_size_Y: - selenium_driver.maximize_window() - else: - if not window_size_X: - window_size_X = 1000 - if not window_size_Y: - window_size_Y = 1000 - selenium_driver.set_window_size(window_size_X, window_size_Y) - CommonUtil.ExecLog(sModuleInfo, "Started Safari Browser", 1) - Shared_Resources.Set_Shared_Variables("selenium_driver", selenium_driver) - CommonUtil.set_screenshot_vars(Shared_Resources.Shared_Variable_Export()) - return "passed" - elif 'browserstack' in browser: - selenium_driver = webdriver.Remote( - command_executor= remote_host, - desired_capabilities=remote_desired_cap) - selenium_driver.implicitly_wait(WebDriver_Wait) - if not window_size_X and not window_size_Y: - selenium_driver.maximize_window() - else: - if not window_size_X: - window_size_X = 1000 - if not window_size_Y: - window_size_Y = 1000 - selenium_driver.set_window_size(window_size_X, window_size_Y) - CommonUtil.ExecLog(sModuleInfo, f"Started {remote_desired_cap['browserName']} on Browserstack", 1) - Shared_Resources.Set_Shared_Variables("selenium_driver", selenium_driver) - CommonUtil.set_screenshot_vars(Shared_Resources.Shared_Variable_Export()) - return "passed" else: CommonUtil.ExecLog( sModuleInfo, "You did not select a valid browser: %s" % browser, 3 ) return "zeuz_failed" - # time.sleep(3) - except SessionNotCreatedException as exc: - return CommonUtil.Exception_Handler(sys.exc_info()) - - except WebDriverException as exc: - return CommonUtil.Exception_Handler(sys.exc_info()) + CommonUtil.ExecLog(sModuleInfo, f"Started {browser} browser", 1) + Shared_Resources.Set_Shared_Variables("selenium_driver", selenium_driver) + CommonUtil.set_screenshot_vars(Shared_Resources.Shared_Variable_Export()) + return "passed" except Exception: return CommonUtil.Exception_Handler(sys.exc_info()) -@deprecated -@logger -def Open_Browser_Wrapper(step_data): - """ Temporary wrapper for open_browser() until that function can be updated to use only data_set """ - - sModuleInfo = inspect.currentframe().f_code.co_name + " : " + MODULE_NAME - - try: - global dependency - # Get the dependency again in case it was missed - if Shared_Resources.Test_Shared_Variables("dependency"): # Check if driver is already set in shared variables - dependency = Shared_Resources.Get_Shared_Variables("dependency") # Retrieve selenium driver - - cmd = step_data[0][2] # Expected "open" or "close" for current method. May contain other strings for old method of Field="open browser" - if cmd.lower().strip() == "close": # User issued close command - try: - selenium_driver.close() - except: - pass - return "passed" - else: # User issued "open" command or used old method of "open browser" - return Open_Browser(dependency) - except Exception: - ErrorMessage = "failed to open browser" - return CommonUtil.Exception_Handler(sys.exc_info(), None, ErrorMessage) - @logger def Open_Empty_Browser(step_data): """Open Empty Browser. @@ -1127,16 +711,6 @@ def Open_Empty_Browser(step_data): if not driver_id: driver_id = "default" - browser_map = { - "Microsoft Edge Chromium": 'msedge', - "Chrome": "chrome", - "FireFox": "firefox", - "Opera": "opera", - "ChromeHeadless": "chrome", - "FirefoxHeadless": "firefox", - "EdgeChromiumHeadless": "msedge", - } - if driver_id not in selenium_details or selenium_details[driver_id]["driver"].capabilities["browserName"].strip().lower() != browser_map[dependency["Browser"]]: if driver_id in selenium_details and selenium_details[driver_id]["driver"].capabilities["browserName"].strip().lower() != browser_map[dependency["Browser"]]: Tear_Down_Selenium() # If dependency is changed then teardown and relaunch selenium driver @@ -1246,34 +820,59 @@ def Go_To_Link_V2(step_data): return "passed" @logger -def Go_To_Link(step_data, page_title=False): - # this function needs work with validating page title. We need to check if user entered any title. - # if not then we don't do the validation - sModuleInfo = inspect.currentframe().f_code.co_name + " : " + MODULE_NAME - window_size_X = ConfigModule.get_config_value("", "window_size_x") - window_size_Y = ConfigModule.get_config_value("", "window_size_y") - - # default capabilities - capabilities = {"unhandledPromptBehavior": "ignore"} - - # options for add_argument or add_extension etc - browser_options = [] - profile_options = [] +def Go_To_Link(dataset: Dataset, page_title=False) -> ReturnType: + try: + sModuleInfo = inspect.currentframe().f_code.co_name + " : " + MODULE_NAME + window_size_X = None + window_size_Y = None + + global initial_download_folder + initial_download_folder = download_dir = ConfigModule.get_config_value("sectionOne", "initial_download_folder", temp_config) + default_chromium_arguments = { + "add_argument": [ + "--ignore-certificate-errors", + "--ignore-ssl-errors", + "--zeuz_pid_finder", + # "--remote-debugging-port=9222", # Required for playright + # "--no-sandbox" + ], + "add_experimental_option": { + "prefs": { + # "profile.default_content_settings.popups": 0, + "download.default_directory": download_dir, + "download.prompt_for_download": False, + # "download.directory_upgrade": True, + # 'safebrowsing.enabled': 'false' + } + }, + "add_extension": [], + "add_encoded_extension": [], + # "page_load_strategy": "normal" + } + browser_options: BrowserOptions = { + "capabilities": { + "unhandledPromptBehavior": "ignore", + # "goog:loggingPrefs": {"performance": "ALL"}, + }, + "chrome": default_chromium_arguments, + "msedge": default_chromium_arguments, + "firefox": {}, + } - # Open browser and create driver if user has not already done so - global dependency - global selenium_driver - global selenium_details - global current_driver_id - if Shared_Resources.Test_Shared_Variables("dependency"): - dependency = Shared_Resources.Get_Shared_Variables("dependency") - else: - raise ValueError("No dependency set - Cannot run") + # Open browser and create driver if user has not already done so + global dependency + global selenium_driver + global selenium_details + global current_driver_id + if Shared_Resources.Test_Shared_Variables("dependency"): + dependency = Shared_Resources.Get_Shared_Variables("dependency") + else: + raise ValueError("No dependency set - Cannot run") - page_load_timeout_sec = 120 - try: + page_load_timeout_sec = 120 + browser = dependency["Browser"].lower() driver_id = "" - for left, mid, right in step_data: + for left, mid, right in dataset: left = left.replace(" ", "").replace("_", "").replace("-", "").lower() if left == "gotolink": web_link = right.strip() @@ -1283,29 +882,33 @@ def Go_To_Link(step_data, page_title=False): Shared_Resources.Set_Shared_Variables("element_wait", float(right.strip())) elif left == "waittimetopageload": page_load_timeout_sec = int(right.strip()) - # checks for capabilities and modifies them by the given step_data - elif mid.strip().lower() == "shared capability": - if left.strip().lower() in ("promptbehavior", "alertbehavior"): - if right.strip().lower() in ("accept", "yes", "ok"): - capabilities["unhandledPromptBehavior"] = "accept" + elif left == "resolution": + resolution = right.split(",") + window_size_X = int(resolution[0]) + window_size_Y = int(resolution[1]) - elif right.strip().lower() in ("dismiss", "no", "cancel"): - capabilities["unhandledPromptBehavior"] = "dismiss" - - else: - # any other shared capabilities can be added from the selenium document - capabilities[left.strip()] = right.strip() - - # Todo: profile, argument, extension, chrome option => go_to_link - elif mid.strip().lower() in ("chrome option", "chrome options") and dependency["Browser"].lower() == "chrome": - browser_options.append([left, right.strip()]) - elif mid.strip().lower() in ("chrome experimental option", "chrome experimental options") and dependency["Browser"].lower() == "chrome": - browser_options.append(["addexperimentaloption", {left.strip():CommonUtil.parse_value_into_object(right.strip())}]) - elif mid.strip().lower() in ("profile option", "profile options"): - profile_options.append([left, right.strip()]) - - if browser_options: - CommonUtil.ExecLog(sModuleInfo, f"Got these browser_options\n{browser_options}", 1) + # Capabilities are WebDriver attribute common across different browser + elif mid.strip().lower() == "shared capability": + browser_options["capabilities"] = CommonUtil.parse_value_into_object(right) + # Options are browser specific. + elif ( + mid.strip().lower() in ("chrome option", "msedge option", "opera option") and + browser == mid.split(" ")[0].strip().lower() or + mid.strip().lower() == "chromium option" and + browser in ("chrome", "msedge", "opera") + ): + if left == "addargument": + browser_options[browser]["add_argument"] = CommonUtil.parse_value_into_object(right) + elif left == "addexperimentaloption": + browser_options[browser]["add_experimental_option"] = CommonUtil.parse_value_into_object(right) + elif left == "addextension": + browser_options[browser]["add_extension"] = CommonUtil.parse_value_into_object(right) + elif left == "addencodedextension": + browser_options[browser]["add_encoded_extension"] = CommonUtil.parse_value_into_object(right) + elif left == "pageloadstrategy": + browser_options[browser]["page_load_strategy"] = right.strip() + + CommonUtil.ExecLog(sModuleInfo, f"browser_options\n{json.dumps(browser_options, indent=2)}", 1) if not driver_id: if len(selenium_details.keys()) == 0: @@ -1313,48 +916,23 @@ def Go_To_Link(step_data, page_title=False): elif current_driver_id is not None: driver_id = current_driver_id else: - driver_id = selenium_details.keys()[0] - - browser_map = { - "Microsoft Edge Chromium": 'msedge', - "Chrome": "chrome", - "FireFox": "firefox", - "Opera": "opera", - "ChromeHeadless": "chrome", - "FirefoxHeadless": "firefox", - "EdgeChromiumHeadless": "msedge", - } - - - is_browserstack = 'browserstack' in dependency["Browser"] - if is_browserstack and driver_id in selenium_details: - selenium_driver = selenium_details[driver_id]["driver"] - Shared_Resources.Set_Shared_Variables("selenium_driver", selenium_driver) + driver_id = list(selenium_details.keys())[0] - elif driver_id not in selenium_details or selenium_details[driver_id]["driver"].capabilities["browserName"].strip().lower() != browser_map[dependency["Browser"]]: + if driver_id not in selenium_details or selenium_details[driver_id]["driver"].capabilities["browserName"].strip().lower() != browser_map[dependency["Browser"]]: if driver_id in selenium_details and selenium_details[driver_id]["driver"].capabilities["browserName"].strip().lower() != browser_map[dependency["Browser"]]: Tear_Down_Selenium() # If dependency is changed then teardown and relaunch selenium driver CommonUtil.ExecLog(sModuleInfo, "Browser not previously opened, doing so now", 1) - if window_size_X == "None" and window_size_Y == "None": - result = Open_Browser(dependency, capability=capabilities, browser_options=browser_options, profile_options=profile_options) - elif window_size_X == "None": - result = Open_Browser(dependency, window_size_Y, capability=capabilities, browser_options=browser_options, profile_options=profile_options) - elif window_size_Y == "None": - result = Open_Browser(dependency, window_size_X, capability=capabilities, browser_options=browser_options, profile_options=profile_options) + result = Open_Browser(dependency["Browser"], browser_options) + + if not window_size_X and not window_size_Y: + selenium_driver.maximize_window() else: - result = Open_Browser(dependency, window_size_X, window_size_Y, capability=capabilities, browser_options=browser_options, profile_options=profile_options) + selenium_driver.set_window_size(window_size_X, window_size_Y) if result == "zeuz_failed": return "zeuz_failed" selenium_details[driver_id] = {"driver": Shared_Resources.Get_Shared_Variables("selenium_driver")} - if selenium_driver.capabilities["browserName"].strip().lower() in ("chrome", "msedge"): - try: - selenium_driver.execute_cdp_cmd("Performance.enable", {}) - except: - CommonUtil.ExecLog( - sModuleInfo, "Unable to execute cdp command - Performance.enable", 3 - ) else: selenium_driver = selenium_details[driver_id]["driver"] @@ -1383,16 +961,7 @@ def Go_To_Link(step_data, page_title=False): # If the browser is closed but selenium instance is on, relaunch selenium_driver if Shared_Resources.Test_Shared_Variables("dependency"): dependency = Shared_Resources.Get_Shared_Variables("dependency") - else: - return CommonUtil.Exception_Handler(sys.exc_info()) - if window_size_X == "None" and window_size_Y == "None": - result = Open_Browser(dependency, capability=capabilities, browser_options=browser_options, profile_options=profile_options) - elif window_size_X == "None": - result = Open_Browser(dependency, window_size_Y, capability=capabilities, browser_options=browser_options, profile_options=profile_options) - elif window_size_Y == "None": - result = Open_Browser(dependency, window_size_X, capability=capabilities, browser_options=browser_options, profile_options=profile_options) - else: - result = Open_Browser(dependency, window_size_X, window_size_Y, capability=capabilities, browser_options=browser_options, profile_options=profile_options) + result = Open_Browser(dependency["Browser"], browser_options) else: result = "zeuz_failed" @@ -1411,46 +980,9 @@ def Go_To_Link(step_data, page_title=False): ErrorMessage = "failed to open your link: %s" % (web_link) return CommonUtil.Exception_Handler(sys.exc_info(), None, ErrorMessage) - # collect_browser_metrics(current_driver_id, CommonUtil.current_action_name) return "passed" -def collect_browser_metrics(driver_id, label): - # Collect custom performance metrics - try: - if selenium_driver.capabilities["browserName"].strip().lower() not in ("chrome", "msedge"): - return {} - - metrics = selenium_driver.execute_cdp_cmd('Performance.getMetrics', {}) - metrics_dict = {} - # FCP - First Contentful Paint - try: metrics_dict["first_contentful_paint"] = selenium_driver.execute_script(JS_FCP) - except: metrics_dict["first_contentful_paint"] = 0 - # LCP - Largest Contenful Paint - try: metrics_dict["largest_contentful_paint"] = selenium_driver.execute_async_script(JS_LCP) - except: metrics_dict["largest_contentful_paint"] = 0 - metrics_dict.update({data["name"]: data["value"] for data in metrics["metrics"]}) - - # Collect identifying information - metrics_dict["label"] = label - metrics_dict["tc_id"] = CommonUtil.current_tc_no - metrics_dict["step_name"] = CommonUtil.current_step_name - metrics_dict["step_sequence"] = CommonUtil.current_step_sequence - metrics_dict["step_id"] = CommonUtil.current_step_id - metrics_dict["time_stamp"] = CommonUtil.get_timestamp() - - if driver_id not in CommonUtil.browser_perf: - CommonUtil.browser_perf[driver_id] = [metrics_dict] - else: - CommonUtil.browser_perf[driver_id].append(metrics_dict) - - # CommonUtil.prettify(key="metrics", val=metrics_dict) - return metrics_dict - except: - return CommonUtil.Exception_Handler(sys.exc_info()) - - - @logger def Handle_Browser_Alert(step_data): # accepts browser alert @@ -3030,24 +2562,6 @@ def Tear_Down_Selenium(step_data=[]): if not driver_id: CommonUtil.Join_Thread_and_Return_Result("screenshot") # Let the capturing screenshot end in thread for driver in selenium_details: - try: - perf_folder = ConfigModule.get_config_value("sectionOne", "performance_report", temp_ini_file) - perf_file = Path(perf_folder)/("matrices_"+driver+".json") - # metrics = selenium_details[driver]["driver"].execute_cdp_cmd('Performance.getMetrics', {}) - # perf_json_data = {data["name"]:data["value"] for data in metrics["metrics"]} - # with open(perf_file, "w", encoding="utf-8") as f: - # json.dump(perf_json_data, f, indent=2) - if selenium_driver.capabilities["browserName"].strip().lower() in ("chrome", "msedge"): - try: - selenium_details[driver]["driver"].execute_cdp_cmd("Performance.disable", {}) - except: - CommonUtil.ExecLog( - sModuleInfo, "Unable to execute cdp command - Performance.enable", 3 - ) - except: - errMsg = "Unable to extract performance metrics of driver_id='%s'" % driver - CommonUtil.ExecLog(sModuleInfo, errMsg, 2) - CommonUtil.Exception_Handler(sys.exc_info(), None, errMsg) try: selenium_details[driver]["driver"].quit() CommonUtil.ExecLog(sModuleInfo, "Teared down driver_id='%s'" % driver, 1) @@ -3064,19 +2578,6 @@ def Tear_Down_Selenium(step_data=[]): else: try: - perf_folder = ConfigModule.get_config_value("sectionOne", "performance_report", temp_ini_file) - perf_file = Path(perf_folder) / ("matrices_" + driver_id + ".json") - # metrics = selenium_details[driver_id]["driver"].execute_cdp_cmd('Performance.getMetrics', {}) - # perf_json_data = {data["name"]: data["value"] for data in metrics["metrics"]} - # with open(perf_file, "w", encoding="utf-8") as f: - # json.dump(perf_json_data, f, indent=2) - if selenium_driver.capabilities["browserName"].strip().lower() in ("chrome", "msedge"): - try: - selenium_details[driver_id]["driver"].execute_cdp_cmd("Performance.disable", {}) - except: - CommonUtil.ExecLog( - sModuleInfo, "Unable to execute cdp command - Performance.enable", 3 - ) selenium_details[driver_id]["driver"].quit() CommonUtil.ExecLog(sModuleInfo, "Teared down driver_id='%s'" % driver_id, 1) except: diff --git a/Framework/Utilities/CommonUtil.py b/Framework/Utilities/CommonUtil.py index b6b111aef..fccd2731f 100644 --- a/Framework/Utilities/CommonUtil.py +++ b/Framework/Utilities/CommonUtil.py @@ -111,7 +111,6 @@ # Holds the previously logged message (used for prevention of duplicate logs simultaneously) previous_log_line = None -teardown = True print_execlog = True show_log = True prettify_limit = 500 @@ -123,7 +122,7 @@ upload_on_fail = True rerun_on_fail = True passed_after_rerun = False -Affirmative_words = ("yes", "true", "on", "ok", "accept", "enable") +affirmative_words = ("yes", "true", "on", "ok", "accept", "enable") negative_words = ("no", "false", "off", "dismiss", "decline", "disable") runid_index = 0 @@ -360,6 +359,8 @@ def strip1(original_value: str, remove: str) -> str: def Exception_Handler(exec_info, temp_q=None, UserMessage=None): try: # console.print_exception(show_locals=True, max_frames=1) + # import traceback + # traceback.print_exc() if performance_testing: return sModuleInfo_Local = inspect.currentframe().f_code.co_name + " : " + MODULE_NAME From 68b81a04b418945ad6d592c9e85ce341f23dc91d Mon Sep 17 00:00:00 2001 From: Muntasib-creator Date: Thu, 10 Oct 2024 21:58:17 +0600 Subject: [PATCH 07/14] Chrome and Edge fixes --- .../action_declarations/info.py | 3 +- .../Sequential_Actions/sequential_actions.py | 2 +- .../Web/Selenium/BuiltInFunctions.py | 94 ++++++------------- 3 files changed, 33 insertions(+), 66 deletions(-) diff --git a/Framework/Built_In_Automation/Sequential_Actions/action_declarations/info.py b/Framework/Built_In_Automation/Sequential_Actions/action_declarations/info.py index 92e43b929..42ca8de0b 100644 --- a/Framework/Built_In_Automation/Sequential_Actions/action_declarations/info.py +++ b/Framework/Built_In_Automation/Sequential_Actions/action_declarations/info.py @@ -83,8 +83,7 @@ "attribute constrain", "optional option", "graphql", - "shared capability", - "chrome option", "chrome options", "chrome experimental option", "chrome experimental options", + "shared capability", "chrome option", "msedge option", "chromium option", "pre sleep", "post sleep", "pre post sleep", "post pre sleep", "zoom parameter", "optional zoom parameter", "pan parameter", "optional pan parameter", "profile option", "profile options", diff --git a/Framework/Built_In_Automation/Sequential_Actions/sequential_actions.py b/Framework/Built_In_Automation/Sequential_Actions/sequential_actions.py index aedba4ef2..62be70ec4 100755 --- a/Framework/Built_In_Automation/Sequential_Actions/sequential_actions.py +++ b/Framework/Built_In_Automation/Sequential_Actions/sequential_actions.py @@ -1084,7 +1084,7 @@ def Run_Sequential_Actions( else: data_set_list.append(i) - if len(data_set_list) == 0 and CommonUtil.debug_status and not sr.Test_Shared_Variables("selenium_driver") and ConfigModule.get_config_value("Inspector", "ai_plugin").strip().lower() in CommonUtil.Affirmative_words: + if len(data_set_list) == 0 and CommonUtil.debug_status and not sr.Test_Shared_Variables("selenium_driver") and ConfigModule.get_config_value("Inspector", "ai_plugin").strip().lower() in CommonUtil.affirmative_words: return Action_Handler([["browser", "selenium action", "browser"]], ["browser", "selenium action", "browser"]), [] for dataset_cnt in data_set_list: # For each data set within step data diff --git a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py index 8509aa00f..b262d64b2 100644 --- a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py +++ b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py @@ -91,6 +91,15 @@ initial_download_folder = None browser_map = { + "Microsoft Edge Chromium": 'microsoftedge', + "Chrome": "chrome", + "FireFox": "firefox", + "Opera": "opera", + "ChromeHeadless": "chrome", + "FirefoxHeadless": "firefox", + "EdgeChromiumHeadless": "microsoftedge", +} +options_map = { "Microsoft Edge Chromium": 'msedge', "Chrome": "chrome", "FireFox": "firefox", @@ -476,19 +485,20 @@ def generate_options(browser: str, browser_options:BrowserOptions): options.add_experimental_option("mobileEmulation", mobile_emulation) for argument in browser_options[b]["add_argument"]: options.add_argument(argument) - for argument in browser_options[b]["add_extension"]: - options.add_extension(argument) - for argument in browser_options[b]["add_encoded_extension"]: - options.add_encoded_extension(argument) + for key, val in browser_options[b]["add_experimental_option"].items(): + options.add_experimental_option(key, val) + for extension in browser_options[b]["add_extension"]: + options.add_extension(extension) + for extension in browser_options[b]["add_encoded_extension"]: + options.add_encoded_extension(extension) if "page_load_strategy" in browser_options[b]: options.page_load_strategy = browser_options[b]["page_load_strategy"] if "headless" in browser: - def chromeheadless(): - options.add_argument( - "--headless=new" - ) - use_xvfb_or_headless(chromeheadless) + def headless(): + arg = "--headless=new" if "chrome" in browser else "--headless" + options.add_argument(arg) + use_xvfb_or_headless(headless) for key, value in browser_options["capabilities"].items(): options.set_capability(key, value) @@ -532,15 +542,16 @@ def Open_Browser(browser, browser_options: BrowserOptions): return "passed" options = generate_options(browser, browser_options) + msg = ( + f"Capabilities: {json.dumps(options.capabilities, indent=2)}\n" + f"Arguments: {json.dumps(options.arguments, indent=2)}\n" + f"Experimental_options: {json.dumps(options.experimental_options, indent=2)}\n" + f"Extensions: {json.dumps(options.extensions, indent=2)}" + ) + CommonUtil.ExecLog(sModuleInfo, msg, 5) + if browser in ("android", "chrome", "chromeheadless"): from selenium.webdriver.chrome.service import Service - if "chromeheadless" in browser: - def chromeheadless(): - options.add_argument( - "--headless=new" - ) - use_xvfb_or_headless(chromeheadless) - service = Service() selenium_driver = webdriver.Chrome( service=service, @@ -559,52 +570,11 @@ def chromeheadless(): firefox_path = ConfigModule.get_config_value("Selenium_driver_paths", "firefox_path") from selenium.webdriver.firefox.service import Service from selenium.webdriver import FirefoxOptions - - if not firefox_path: - firefox_path = GeckoDriverManager().install() - ConfigModule.add_config_value("Selenium_driver_paths", "firefox_path", firefox_path) - from sys import platform as _platform - options = FirefoxOptions() - - if profile_options: - for left, right in profile_options: - if left in ("addargument", "addarguments"): - options.add_argument(right.strip()) - print(left, right) - - if remote_browser_version: - options.set_capability("browserVersion",remote_browser_version) + from selenium.webdriver.firefox.options import Options if "headless" in browser: #firefox headless mode needs add_argument options.add_argument("-headless") - # options.headless = True - - ''' - # commenting out as this is not working. Make sure - # whoever implemented this it is tested with latest firefox version - def firefoxheadless(): - options.headless = True - use_xvfb_or_headless(firefoxheadless) - ''' - - if _platform == "win32": - try: - import winreg - except ImportError: - import _winreg as winreg - handle = winreg.OpenKey( - winreg.HKEY_LOCAL_MACHINE, - r"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\firefox.exe", - ) - num_values = winreg.QueryInfoKey(handle)[1] - path = False - for i in range(num_values): - path = winreg.EnumValue(handle, i) - if path != False: - Firefox_path = path[1] - binary = FirefoxBinary(Firefox_path) - break profile = webdriver.FirefoxProfile() initial_download_folder = download_dir = ConfigModule.get_config_value("sectionOne", "initial_download_folder", temp_config) @@ -870,7 +840,7 @@ def Go_To_Link(dataset: Dataset, page_title=False) -> ReturnType: raise ValueError("No dependency set - Cannot run") page_load_timeout_sec = 120 - browser = dependency["Browser"].lower() + browser = options_map[dependency["Browser"]] driver_id = "" for left, mid, right in dataset: left = left.replace(" ", "").replace("_", "").replace("-", "").lower() @@ -892,10 +862,10 @@ def Go_To_Link(dataset: Dataset, page_title=False) -> ReturnType: browser_options["capabilities"] = CommonUtil.parse_value_into_object(right) # Options are browser specific. elif ( - mid.strip().lower() in ("chrome option", "msedge option", "opera option") and + mid.strip().lower() in ("chrome option", "msedge option") and browser == mid.split(" ")[0].strip().lower() or mid.strip().lower() == "chromium option" and - browser in ("chrome", "msedge", "opera") + browser in ("chrome", "msedge") ): if left == "addargument": browser_options[browser]["add_argument"] = CommonUtil.parse_value_into_object(right) @@ -908,8 +878,6 @@ def Go_To_Link(dataset: Dataset, page_title=False) -> ReturnType: elif left == "pageloadstrategy": browser_options[browser]["page_load_strategy"] = right.strip() - CommonUtil.ExecLog(sModuleInfo, f"browser_options\n{json.dumps(browser_options, indent=2)}", 1) - if not driver_id: if len(selenium_details.keys()) == 0: driver_id = "default" From 72c230bf69cd5b18e9a4f94b1526a3be9b3f9d4b Mon Sep 17 00:00:00 2001 From: Muntasib-creator Date: Sat, 12 Oct 2024 09:57:01 +0600 Subject: [PATCH 08/14] Chrome, Edge, Firefox fixes --- .../action_declarations/info.py | 2 +- .../Web/Selenium/BuiltInFunctions.py | 241 ++++++------------ Framework/Utilities/CommonUtil.py | 19 +- 3 files changed, 85 insertions(+), 177 deletions(-) diff --git a/Framework/Built_In_Automation/Sequential_Actions/action_declarations/info.py b/Framework/Built_In_Automation/Sequential_Actions/action_declarations/info.py index 42ca8de0b..b1dfdaa05 100644 --- a/Framework/Built_In_Automation/Sequential_Actions/action_declarations/info.py +++ b/Framework/Built_In_Automation/Sequential_Actions/action_declarations/info.py @@ -83,7 +83,7 @@ "attribute constrain", "optional option", "graphql", - "shared capability", "chrome option", "msedge option", "chromium option", + "shared capability", "chrome option", "edge option", "chromium option", "pre sleep", "post sleep", "pre post sleep", "post pre sleep", "zoom parameter", "optional zoom parameter", "pan parameter", "optional pan parameter", "profile option", "profile options", diff --git a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py index b262d64b2..97b159976 100644 --- a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py +++ b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py @@ -100,13 +100,13 @@ "EdgeChromiumHeadless": "microsoftedge", } options_map = { - "Microsoft Edge Chromium": 'msedge', + "Microsoft Edge Chromium": "edge", "Chrome": "chrome", "FireFox": "firefox", "Opera": "opera", "ChromeHeadless": "chrome", "FirefoxHeadless": "firefox", - "EdgeChromiumHeadless": "msedge", + "EdgeChromiumHeadless": "edge", } from typing import Literal, TypedDict, Any, Union, NotRequired @@ -120,11 +120,19 @@ class DefaultChromiumArguments(TypedDict): add_encoded_extension: list[str] page_load_strategy: NotRequired[Literal["normal", "eager", "none"]] +class FirefoxArguments(TypedDict): + add_argument: list[str] + set_preference: dict[str, dict[str, Any]] + +class SafariArguments(TypedDict): + add_argument: list[str] + class BrowserOptions(TypedDict): capabilities: dict[str,Any] chrome: DefaultChromiumArguments - msedge: DefaultChromiumArguments - firefox: Any + edge: DefaultChromiumArguments + firefox: FirefoxArguments + safari: SafariArguments from selenium.webdriver.common.options import ArgOptions @@ -475,11 +483,15 @@ def set_extension_variables(): def generate_options(browser: str, browser_options:BrowserOptions): """ Adds capabilities and options for Browser/WebDriver """ - if browser in ("android", "chrome", "chromeheadless", "microsoft edge chromium", "edgechromiumheadless"): - b = "msedge" if "edge" in browser else "chrome" + sModuleInfo = inspect.currentframe().f_code.co_name + " : " + MODULE_NAME + chromium_condition = browser in ("android", "chrome", "chromeheadless", "microsoft edge chromium", "edgechromiumheadless") + if chromium_condition: + b = "edge" if "edge" in browser else "chrome" from selenium.webdriver.chrome.options import Options as ChromeOptions from selenium.webdriver.edge.options import Options as EdgeOptions options = ChromeOptions() if b == "chrome" else EdgeOptions() + # from selenium.webdriver.chromium.options import ChromiumOptions + # options = ChromiumOptions() if browser == "android": mobile_emulation = {"deviceName": "Pixel 2 XL"} options.add_experimental_option("mobileEmulation", mobile_emulation) @@ -494,6 +506,22 @@ def generate_options(browser: str, browser_options:BrowserOptions): if "page_load_strategy" in browser_options[b]: options.page_load_strategy = browser_options[b]["page_load_strategy"] + elif browser in ("firefox", "firefoxheadless"): + from selenium.webdriver.firefox.options import Options as FirefoxOptions + options = FirefoxOptions() + for argument in browser_options["firefox"]["add_argument"]: + options.add_argument(argument) + for key, val in browser_options["firefox"]["set_preference"].items(): + options.set_preference(key, val) + + elif "safari" in browser: + from selenium.webdriver.safari.options import Options + options = Options() + for argument in browser_options["safari"]["add_argument"]: + options.add_argument(argument) + else: + return None + if "headless" in browser: def headless(): arg = "--headless=new" if "chrome" in browser else "--headless" @@ -513,6 +541,13 @@ def headless(): options.add_argument(f"load-extension={aiplugin_path},{ai_recorder_path}") # This is for running extension on a http server to call a https request options.add_argument("--allow-running-insecure-content") + + msg = f"Capabilities: {json.dumps(options.capabilities, indent=2)}\n" + \ + f"Arguments: {json.dumps(options.arguments, indent=2)}\n" + \ + f"Experimental_options: {json.dumps(options.experimental_options, indent=2)}\n" if chromium_condition else "" + \ + f"Extensions: {json.dumps(options.extensions, indent=2)}\n" if chromium_condition else "" + \ + f"Preferences: {json.dumps(options.preferences, indent=2)}" if "firefox" in browser else "" + CommonUtil.ExecLog(sModuleInfo, msg, 5) return options @logger @@ -542,14 +577,6 @@ def Open_Browser(browser, browser_options: BrowserOptions): return "passed" options = generate_options(browser, browser_options) - msg = ( - f"Capabilities: {json.dumps(options.capabilities, indent=2)}\n" - f"Arguments: {json.dumps(options.arguments, indent=2)}\n" - f"Experimental_options: {json.dumps(options.experimental_options, indent=2)}\n" - f"Extensions: {json.dumps(options.extensions, indent=2)}" - ) - CommonUtil.ExecLog(sModuleInfo, msg, 5) - if browser in ("android", "chrome", "chromeheadless"): from selenium.webdriver.chrome.service import Service service = Service() @@ -567,68 +594,20 @@ def Open_Browser(browser, browser_options: BrowserOptions): ) elif browser in ("firefox", "firefoxheadless"): - firefox_path = ConfigModule.get_config_value("Selenium_driver_paths", "firefox_path") from selenium.webdriver.firefox.service import Service - from selenium.webdriver import FirefoxOptions - from selenium.webdriver.firefox.options import Options - - if "headless" in browser: - #firefox headless mode needs add_argument - options.add_argument("-headless") - - profile = webdriver.FirefoxProfile() - initial_download_folder = download_dir = ConfigModule.get_config_value("sectionOne", "initial_download_folder", temp_config) - profile.set_preference("browser.download.folderList", 2) - profile.set_preference("browser.download.manager.showWhenStarting", False) - profile.set_preference("browser.download.dir", download_dir) - #text/plain;charset=UTF-8 - # Allowing txt, pdf, xlsx, xml, csv, zip files to be directly downloaded without save prompt - apps = "application/pdf;text/plain;application/text;text/xml;application/xml;application/xlsx;application/csv;application/zip" - profile.set_preference("browser.helperApps.neverAsk.saveToDisk", apps) - profile.accept_untrusted_certs = True - - options.set_preference("browser.download.folderList", 2) - options.set_preference("browser.download.manager.showWhenStarting", False) - options.set_preference("browser.download.dir", download_dir) - options.set_preference("browser.helperApps.neverAsk.saveToDisk", apps) - options.accept_untrusted_certs = True - - if remote_host: - capabilities = webdriver.DesiredCapabilities().FIREFOX - capabilities['acceptSslCerts'] = True - selenium_driver = webdriver.Remote( - command_executor= remote_host + "wd/hub", - options=options, - ) - else: - service = Service() - selenium_driver = webdriver.Firefox( - service=service, - options=options, - ) - + service = Service() + selenium_driver = webdriver.Firefox( + service=service, + options=options, + ) elif "safari" in browser: - CommonUtil.ExecLog(sModuleInfo, "Restart computer after following ... https://developer.apple.com/documentation/webkit/testing_with_webdriver_in_safari ", 1) - ''' - os.environ["SELENIUM_SERVER_JAR"] = ( - os.sys.prefix - + os.sep - + "Scripts" - + os.sep - + "selenium-server-standalone-2.45.0.jar" - )''' - - desired_capabilities = DesiredCapabilities.SAFARI - - if "ios" in browser: - desired_capabilities["platformName"] = "ios" - - if "simulator" in browser: - desired_capabilities["safari:useSimulator"] = True - - selenium_driver = webdriver.Safari(desired_capabilities=desired_capabilities) - + from selenium.webdriver.safari.service import Service + service = Service() + selenium_driver = webdriver.Safari( + service=service, + options=options, + ) else: CommonUtil.ExecLog( sModuleInfo, "You did not select a valid browser: %s" % browser, 3 @@ -798,6 +777,7 @@ def Go_To_Link(dataset: Dataset, page_title=False) -> ReturnType: global initial_download_folder initial_download_folder = download_dir = ConfigModule.get_config_value("sectionOne", "initial_download_folder", temp_config) + apps = "application/pdf;text/plain;application/text;text/xml;application/xml;application/xlsx;application/csv;application/zip" default_chromium_arguments = { "add_argument": [ "--ignore-certificate-errors", @@ -825,10 +805,23 @@ def Go_To_Link(dataset: Dataset, page_title=False) -> ReturnType: # "goog:loggingPrefs": {"performance": "ALL"}, }, "chrome": default_chromium_arguments, - "msedge": default_chromium_arguments, - "firefox": {}, + "edge": default_chromium_arguments, + "firefox": { + "add_argument": [], + "set_preference": { + "browser.download.folderList": 2, + "browser.download.manager.showWhenStarting": False, + "browser.download.dir": download_dir, + "browser.helperApps.neverAsk.saveToDisk": apps, + "browser.download.useDownloadDir": True, + "browser.download.manager.closeWhenDone": True, + "security.mixed_content.block_active_content": False, + } + }, + "safari": { + "add_argument": [], + } } - # Open browser and create driver if user has not already done so global dependency global selenium_driver @@ -862,10 +855,10 @@ def Go_To_Link(dataset: Dataset, page_title=False) -> ReturnType: browser_options["capabilities"] = CommonUtil.parse_value_into_object(right) # Options are browser specific. elif ( - mid.strip().lower() in ("chrome option", "msedge option") and + mid.strip().lower() in ("chrome option", "edge option") and browser == mid.split(" ")[0].strip().lower() or mid.strip().lower() == "chromium option" and - browser in ("chrome", "msedge") + browser in ("chrome", "edge") ): if left == "addargument": browser_options[browser]["add_argument"] = CommonUtil.parse_value_into_object(right) @@ -924,7 +917,7 @@ def Go_To_Link(dataset: Dataset, page_title=False) -> ReturnType: CommonUtil.ExecLog(sModuleInfo, "Successfully opened your link with driver_id='%s': %s" % (driver_id, web_link), 1) except WebDriverException as e: browser = selenium_driver.capabilities["browserName"].strip().lower() - if (browser in ("chrome", "msedge", "opera") and e.msg.lower().startswith("chrome not reachable")) or (browser == "firefox" and e.msg.lower().startswith("tried to run command without establishing a connection")): + if (browser in ("chrome", "edge") and e.msg.lower().startswith("chrome not reachable")) or (browser == "firefox" and e.msg.lower().startswith("tried to run command without establishing a connection")): CommonUtil.ExecLog(sModuleInfo, "Browser not found. trying to restart the browser", 2) # If the browser is closed but selenium instance is on, relaunch selenium_driver if Shared_Resources.Test_Shared_Variables("dependency"): @@ -1503,7 +1496,7 @@ def Click_and_Download(data_set): sModuleInfo = inspect.currentframe().f_code.co_name + " : " + MODULE_NAME global selenium_driver - if selenium_driver.capabilities["browserName"].strip().lower() not in ("chrome", "msedge", "firefox"): + if selenium_driver.capabilities["browserName"].strip().lower() not in ("chrome", "microsoftedge", "firefox"): CommonUtil.ExecLog(sModuleInfo, "This action was made for Chrome, MS Edge and Firefox. Other browsers won't download files in Zeuz_Download_Folder", 2) #Todo: @@ -1591,7 +1584,7 @@ def Click_and_Download(data_set): pyautogui.hotkey("down") pyautogui.hotkey("enter") - if selenium_driver.capabilities["browserName"].strip().lower() in ("chrome", "msedge", "firefox"): + if selenium_driver.capabilities["browserName"].strip().lower() in ("chrome", "microsoftedge", "firefox"): CommonUtil.ExecLog(sModuleInfo, "Download started. Will wait max %s seconds..." % wait_download, 1) s = time.perf_counter() if selenium_driver.capabilities["browserName"].strip().lower() == "firefox": @@ -3006,7 +2999,6 @@ def upload_file_through_window(step_data): global selenium_driver all_file_path = [] pid = "" - send_keys_flag = False import pyautogui if "headless" in dependency: CommonUtil.ExecLog(sModuleInfo, "This action will not work on headless browsers", 3) @@ -3021,8 +3013,6 @@ def upload_file_through_window(step_data): all_file_path.append(path) else: CommonUtil.ExecLog(sModuleInfo, "Could not find any directory or file with the path: %s" % path, 3) - if "keys" in l: - send_keys_flag = True if len(all_file_path) == 0: CommonUtil.ExecLog(sModuleInfo, "Could not find any valid filepath or directory", 3) @@ -3033,23 +3023,8 @@ def upload_file_through_window(step_data): return CommonUtil.Exception_Handler(sys.exc_info(), None, "Error parsing dataset") try: - - if platform.system() == "Darwin": - # Will require pid when we will atomate with atomacos module. Fetching PID is only tested on Chrome for now - if selenium_driver.capabilities["browserName"].lower() == "chrome": - for process in psutil.process_iter(): - try: - if process.name() == 'Google Chrome' and '--test-type=webdriver' in process.cmdline() and "--zeuz_pid_finder" in process.cmdline(): - pid = str(process.pid) - break - except Exception as e: - # print(e) - pass - path_name = path_name[1:-1] - - import pyautogui time.sleep(3) pyautogui.hotkey("/") time.sleep(5) @@ -3061,14 +3036,6 @@ def upload_file_through_window(step_data): time.sleep(2) pyautogui.hotkey("enter") - elif send_keys_flag is True: - - file_input = selenium_driver.find_element(By.XPATH, "//input[@type='file']") - - file_path = path_name[1:-1] - file_input.send_keys(file_path) - - # window_ds = ("*window", "element parameter", selenium_driver.title) elif platform.system() == "Windows": if selenium_driver.capabilities["browserName"].lower() == "firefox": @@ -3081,7 +3048,7 @@ def upload_file_through_window(step_data): for process in psutil.process_iter(): if process.name() == 'opera.exe' and '--test-type=webdriver' in process.cmdline() and "--zeuz_pid_finder" in process.cmdline(): pid = str(process.pid) - elif selenium_driver.capabilities["browserName"].lower() == "msedge": + elif selenium_driver.capabilities["browserName"].lower() == "microsoftedge": for process in psutil.process_iter(): if process.name() == 'msedge.exe' and '--test-type=webdriver' in process.cmdline() and "--zeuz_pid_finder" in process.cmdline(): pid = str(process.pid) @@ -3110,7 +3077,7 @@ def upload_file_through_window(step_data): # else: # pid = str(win_pids[0]) - if selenium_driver.capabilities["browserName"].lower() not in ("firefox", "chrome", "opera", "msedge"): + if selenium_driver.capabilities["browserName"].lower() not in ("firefox", "chrome", "opera", "microsoftedge"): win_pids = get_pids_from_title(selenium_driver.title) if len(win_pids) == 0: CommonUtil.ExecLog(sModuleInfo, "Could not find the pid for browser. Switching to GUI method", 2) @@ -3271,65 +3238,17 @@ def drag_and_drop(dataset): CommonUtil.ExecLog(sModuleInfo, "Destination Element is not found", 3) return "zeuz_failed" - """ The following code does not work with mentioned delay time. delay=2 takes 25 seconds for a dnd """ - # if delay: - # if destination_offset: - # destination_x, destination_y = get_offsets(destination_offset, destination_element) - # else: - # destination_x = destination_element.location['x'] - # destination_y = destination_element.location['y'] - # distance_x = destination_x - source_element.location['x'] - # distance_y = destination_y - source_element.location['y'] - # total_time = delay - # total_distance = (distance_x**2 + distance_y**2)**0.5 - # - # pixels_per_step = 5 - # steps = int(total_distance / pixels_per_step) - # - # # Calculate the ideal time per step to fit within the total time - # ideal_time_per_step = total_time / steps - # - # # Start the high-resolution timer - # start_time = time.perf_counter() - # - # # Create an ActionChains object - # actions = ActionChains(selenium_driver) - # - # # Click and hold the source element - # actions.click_and_hold(source_element).perform() - # - # # Manually move the mouse to the target element in small increments - # for i in range(steps): - # # Calculate the movement for this step - # move_x = distance_x / steps - # move_y = distance_y / steps - # - # # Move the mouse by the calculated offset - # actions.move_by_offset(move_x, move_y).perform() - # - # # Calculate elapsed time and adjust the sleep time - # elapsed_time = time.perf_counter() - start_time - # remaining_time = total_time - elapsed_time - # time_per_step = remaining_time / (steps - i) - # - # if time_per_step > 0: - # time.sleep(time_per_step) - # - # # Release the mouse button to drop the element - # actions.release().perform() - # sleep(2) - if destination_offset: x, y = get_offsets(destination_offset, destination_element) - if delay: + if delay is not None: """ This line of code was not tested, just keeping here""" - ActionChains(selenium_driver).click_and_hold(source_element).move_to_element_with_offset(destination_element, x, y).pause(0.5).release().perform() + ActionChains(selenium_driver).click_and_hold(source_element).move_to_element_with_offset(destination_element, x, y).pause(delay).release().perform() else: ActionChains(selenium_driver).click_and_hold(source_element).move_to_element_with_offset(destination_element, x, y).release().perform() else: - if delay: - ActionChains(selenium_driver).click_and_hold(source_element).move_to_element(destination_element).pause(0.5).release(destination_element).perform() + if delay is not None: + ActionChains(selenium_driver).click_and_hold(source_element).move_to_element(destination_element).pause(delay).release(destination_element).perform() else: ActionChains(selenium_driver).drag_and_drop(source_element, destination_element).perform() diff --git a/Framework/Utilities/CommonUtil.py b/Framework/Utilities/CommonUtil.py index fccd2731f..f202455d5 100644 --- a/Framework/Utilities/CommonUtil.py +++ b/Framework/Utilities/CommonUtil.py @@ -43,6 +43,7 @@ # Import colorama for console color support from colorama import init as colorama_init from colorama import Fore, Back, Style +import traceback # Initialize colorama for the current platform colorama_init(autoreset=True) @@ -358,27 +359,15 @@ def strip1(original_value: str, remove: str) -> str: def Exception_Handler(exec_info, temp_q=None, UserMessage=None): try: - # console.print_exception(show_locals=True, max_frames=1) - # import traceback - # traceback.print_exc() if performance_testing: return + sModuleInfo_Local = inspect.currentframe().f_code.co_name + " : " + MODULE_NAME exc_type, exc_obj, exc_tb = exec_info - Error_Type = ( - (str(exc_type).replace("type ", "")) - .replace("<", "") - .replace(">", "") - .replace(";", ":") - ) - Error_Message = str(exc_obj) File_Name = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] Function_Name = os.path.split(exc_tb.tb_frame.f_code.co_name)[1] - Line_Number = str(exc_tb.tb_lineno) - Error_Detail = ( - "Error Type ~ %s: Error Message ~ %s: File Name ~ %s: Function Name ~ %s: Line ~ %s" - % (Error_Type, Error_Message, File_Name, Function_Name, Line_Number) - ) + if debug_status: + Error_Detail = traceback.format_exc() sModuleInfo = Function_Name + ":" + File_Name ExecLog(sModuleInfo, "Following exception occurred: %s" % (Error_Detail), 3) # TakeScreenShot(Function_Name + "~" + File_Name) From 58acee68529e1f5bf0a611851fdfe262b5da7328 Mon Sep 17 00:00:00 2001 From: Muntasib-creator Date: Sat, 12 Oct 2024 10:11:07 +0600 Subject: [PATCH 09/14] msg fix --- .../Web/Selenium/BuiltInFunctions.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py index 97b159976..ac3ebb7d7 100644 --- a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py +++ b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py @@ -485,6 +485,7 @@ def generate_options(browser: str, browser_options:BrowserOptions): """ Adds capabilities and options for Browser/WebDriver """ sModuleInfo = inspect.currentframe().f_code.co_name + " : " + MODULE_NAME chromium_condition = browser in ("android", "chrome", "chromeheadless", "microsoft edge chromium", "edgechromiumheadless") + msg = "" if chromium_condition: b = "edge" if "edge" in browser else "chrome" from selenium.webdriver.chrome.options import Options as ChromeOptions @@ -505,7 +506,10 @@ def generate_options(browser: str, browser_options:BrowserOptions): options.add_encoded_extension(extension) if "page_load_strategy" in browser_options[b]: options.page_load_strategy = browser_options[b]["page_load_strategy"] - + msg += ( + f"Experimental_options: {json.dumps(options.experimental_options, indent=2)}\n" + f"Extensions: {json.dumps(options.extensions, indent=2)}\n" + ) elif browser in ("firefox", "firefoxheadless"): from selenium.webdriver.firefox.options import Options as FirefoxOptions options = FirefoxOptions() @@ -513,7 +517,9 @@ def generate_options(browser: str, browser_options:BrowserOptions): options.add_argument(argument) for key, val in browser_options["firefox"]["set_preference"].items(): options.set_preference(key, val) - + msg += ( + f"Preferences: {json.dumps(options.preferences, indent=2)}\n" + ) elif "safari" in browser: from selenium.webdriver.safari.options import Options options = Options() @@ -542,11 +548,10 @@ def headless(): # This is for running extension on a http server to call a https request options.add_argument("--allow-running-insecure-content") - msg = f"Capabilities: {json.dumps(options.capabilities, indent=2)}\n" + \ - f"Arguments: {json.dumps(options.arguments, indent=2)}\n" + \ - f"Experimental_options: {json.dumps(options.experimental_options, indent=2)}\n" if chromium_condition else "" + \ - f"Extensions: {json.dumps(options.extensions, indent=2)}\n" if chromium_condition else "" + \ - f"Preferences: {json.dumps(options.preferences, indent=2)}" if "firefox" in browser else "" + msg += ( + f"Capabilities: {json.dumps(options.capabilities, indent=2)}\n" + + f"Arguments: {json.dumps(options.arguments, indent=2)}\n" + ) CommonUtil.ExecLog(sModuleInfo, msg, 5) return options From e5575dee07709ce085b8730051daaeab1f130d10 Mon Sep 17 00:00:00 2001 From: test Date: Sat, 12 Oct 2024 11:17:20 +0600 Subject: [PATCH 10/14] safari, firefox fix, datatype validation --- .../action_declarations/info.py | 2 +- .../Web/Selenium/BuiltInFunctions.py | 54 ++++++++++++++----- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/Framework/Built_In_Automation/Sequential_Actions/action_declarations/info.py b/Framework/Built_In_Automation/Sequential_Actions/action_declarations/info.py index b1dfdaa05..7ab3ce573 100644 --- a/Framework/Built_In_Automation/Sequential_Actions/action_declarations/info.py +++ b/Framework/Built_In_Automation/Sequential_Actions/action_declarations/info.py @@ -83,7 +83,7 @@ "attribute constrain", "optional option", "graphql", - "shared capability", "chrome option", "edge option", "chromium option", + "shared capability", "chrome option", "edge option", "chromium option", "firefox option", "safari option", "pre sleep", "post sleep", "pre post sleep", "post pre sleep", "zoom parameter", "optional zoom parameter", "pan parameter", "optional pan parameter", "profile option", "profile options", diff --git a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py index ac3ebb7d7..7dc875a54 100644 --- a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py +++ b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py @@ -98,6 +98,7 @@ "ChromeHeadless": "chrome", "FirefoxHeadless": "firefox", "EdgeChromiumHeadless": "microsoftedge", + "Safari": "safari" } options_map = { "Microsoft Edge Chromium": "edge", @@ -107,6 +108,7 @@ "ChromeHeadless": "chrome", "FirefoxHeadless": "firefox", "EdgeChromiumHeadless": "edge", + "Safari": "safari" } from typing import Literal, TypedDict, Any, Union, NotRequired @@ -115,14 +117,14 @@ class DefaultChromiumArguments(TypedDict): add_argument: list[str] - add_experimental_option: dict[str, dict[str, Any]] + add_experimental_option: dict[str, Any] add_extension: list[str] add_encoded_extension: list[str] page_load_strategy: NotRequired[Literal["normal", "eager", "none"]] class FirefoxArguments(TypedDict): add_argument: list[str] - set_preference: dict[str, dict[str, Any]] + set_preference: dict[str, Any] class SafariArguments(TypedDict): add_argument: list[str] @@ -517,16 +519,20 @@ def generate_options(browser: str, browser_options:BrowserOptions): options.add_argument(argument) for key, val in browser_options["firefox"]["set_preference"].items(): options.set_preference(key, val) + if "page_load_strategy" in browser_options["firefox"]: + options.page_load_strategy = browser_options["firefox"]["page_load_strategy"] msg += ( f"Preferences: {json.dumps(options.preferences, indent=2)}\n" ) elif "safari" in browser: - from selenium.webdriver.safari.options import Options - options = Options() + from selenium.webdriver.safari.options import Options as SafariOptions + options = SafariOptions() for argument in browser_options["safari"]["add_argument"]: options.add_argument(argument) + if "page_load_strategy" in browser_options["safari"]: + options.page_load_strategy = browser_options["safari"]["page_load_strategy"] else: - return None + raise Exception if "headless" in browser: def headless(): @@ -773,6 +779,29 @@ def Go_To_Link_V2(step_data): CommonUtil.set_screenshot_vars(Shared_Resources.Shared_Variable_Export()) return "passed" + +def parse_and_verify_datatype(left:str, right:str): + val = CommonUtil.parse_value_into_object(right) + if left == "addargument": + if isinstance(val, list) and all(isinstance(item, str) for item in val): + return val + raise ValueError("Argument must be list of strings. Example: ['--ignore-ssl-errors', '--no-sandbox']") + + if left == "addextension": + if isinstance(val, list) and all(isinstance(item, str) for item in val): + return val + raise ValueError("Extensions must be list of strings. Example: ['path/to/ex1.crx', 'path/to/ex2.crx']") + + if left == "addencodedextension": + if isinstance(val, list) and all(isinstance(item, str) for item in val): + return val + raise ValueError("Encoded_extenions must be list of strings. Example: ['ex1_encoded_str', 'ex2_encoded_str']") + + elif left == "addexperimentaloption": + if isinstance(val, dict): + return val + raise ValueError('Experimental_option must be dictionary. Example: {"mobileEmulation":{"deviceName": "Pixel 2 XL"}}') + @logger def Go_To_Link(dataset: Dataset, page_title=False) -> ReturnType: try: @@ -860,19 +889,20 @@ def Go_To_Link(dataset: Dataset, page_title=False) -> ReturnType: browser_options["capabilities"] = CommonUtil.parse_value_into_object(right) # Options are browser specific. elif ( - mid.strip().lower() in ("chrome option", "edge option") and - browser == mid.split(" ")[0].strip().lower() or mid.strip().lower() == "chromium option" and - browser in ("chrome", "edge") + browser in ("chrome", "edge") or + browser == mid.split(" ")[0].strip().lower() ): if left == "addargument": - browser_options[browser]["add_argument"] = CommonUtil.parse_value_into_object(right) + browser_options[browser]["add_argument"] = parse_and_verify_datatype(left, right) elif left == "addexperimentaloption": - browser_options[browser]["add_experimental_option"] = CommonUtil.parse_value_into_object(right) + browser_options[browser]["add_experimental_option"] = parse_and_verify_datatype(left, right) elif left == "addextension": - browser_options[browser]["add_extension"] = CommonUtil.parse_value_into_object(right) + browser_options[browser]["add_extension"] = parse_and_verify_datatype(left, right) elif left == "addencodedextension": - browser_options[browser]["add_encoded_extension"] = CommonUtil.parse_value_into_object(right) + browser_options[browser]["add_encoded_extension"] = parse_and_verify_datatype(left, right) + elif left == "setpreference": + browser_options[browser]["set_preference"] = parse_and_verify_datatype(left, right) elif left == "pageloadstrategy": browser_options[browser]["page_load_strategy"] = right.strip() From c7bc636b4802e729f1e554ec232bc00e2de89c79 Mon Sep 17 00:00:00 2001 From: test Date: Sat, 12 Oct 2024 11:31:55 +0600 Subject: [PATCH 11/14] Open_Empty_Browser fix --- .../action_declarations/selenium.py | 2 +- .../Web/Selenium/BuiltInFunctions.py | 81 +++---------------- 2 files changed, 11 insertions(+), 72 deletions(-) diff --git a/Framework/Built_In_Automation/Sequential_Actions/action_declarations/selenium.py b/Framework/Built_In_Automation/Sequential_Actions/action_declarations/selenium.py index 56c210c5e..baacac6c1 100644 --- a/Framework/Built_In_Automation/Sequential_Actions/action_declarations/selenium.py +++ b/Framework/Built_In_Automation/Sequential_Actions/action_declarations/selenium.py @@ -17,7 +17,7 @@ { "name": "deselect by value", "function": "Select_Deselect", "screenshot": "web" }, { "name": "select by index", "function": "Select_Deselect", "screenshot": "web" }, { "name": "deselect by index", "function": "Select_Deselect", "screenshot": "web" }, - { "name": "open browser", "function": "Open_Empty_Browser", "screenshot": "web" }, + { "name": "open browser", "function": "Go_To_Link", "screenshot": "web" }, { "name": "open electron app", "function": "Open_Electron_App", "screenshot": "web" }, { "name": "go to link", "function": "Go_To_Link", "screenshot": "web" }, { "name": "go to link v2", "function": "Go_To_Link_V2", "screenshot": "web" }, diff --git a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py index 7dc875a54..8c6f99d5d 100644 --- a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py +++ b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py @@ -634,70 +634,6 @@ def Open_Browser(browser, browser_options: BrowserOptions): return CommonUtil.Exception_Handler(sys.exc_info()) -@logger -def Open_Empty_Browser(step_data): - """Open Empty Browser. - - Args: - data_set: - open browser | selenium action | open - - Returns: - "passed" if browser open is successful. - "zeuz_failed" otherwise. - """ - sModuleInfo = inspect.currentframe().f_code.co_name + " : " + MODULE_NAME - - window_size_X = ConfigModule.get_config_value("", "window_size_x") - window_size_Y = ConfigModule.get_config_value("", "window_size_y") - # Open browser and create driver if user has not already done so - global dependency - global selenium_driver - global selenium_details - global current_driver_id - - if Shared_Resources.Test_Shared_Variables("dependency"): - dependency = Shared_Resources.Get_Shared_Variables("dependency") - else: - raise ValueError("No dependency set - Cannot run") - - try: - driver_id = "" - for left, mid, right in step_data: - left = left.replace(" ", "").replace("_", "").replace("-", "").lower() - if left == "driverid": - driver_id = right.strip() - - if not driver_id: - driver_id = "default" - - if driver_id not in selenium_details or selenium_details[driver_id]["driver"].capabilities["browserName"].strip().lower() != browser_map[dependency["Browser"]]: - if driver_id in selenium_details and selenium_details[driver_id]["driver"].capabilities["browserName"].strip().lower() != browser_map[dependency["Browser"]]: - Tear_Down_Selenium() # If dependency is changed then teardown and relaunch selenium driver - CommonUtil.ExecLog(sModuleInfo, "Browser not previously opened, doing so now", 1) - if window_size_X == "None" and window_size_Y == "None": - result = Open_Browser(dependency) - elif window_size_X == "None": - result = Open_Browser(dependency, window_size_Y) - elif window_size_Y == "None": - result = Open_Browser(dependency, window_size_X) - else: - result = Open_Browser(dependency, window_size_X, window_size_Y) - - if result == "zeuz_failed": - return "zeuz_failed" - - selenium_details[driver_id] = {"driver": Shared_Resources.Get_Shared_Variables("selenium_driver")} - - else: - selenium_driver = selenium_details[driver_id]["driver"] - Shared_Resources.Set_Shared_Variables("selenium_driver", selenium_driver) - - return "passed" - except Exception: - ErrorMessage = "failed to open browser" - return CommonUtil.Exception_Handler(sys.exc_info(), None, ErrorMessage) - @logger def Go_To_Link_V2(step_data): from selenium.webdriver.chrome.options import Options @@ -803,7 +739,7 @@ def parse_and_verify_datatype(left:str, right:str): raise ValueError('Experimental_option must be dictionary. Example: {"mobileEmulation":{"deviceName": "Pixel 2 XL"}}') @logger -def Go_To_Link(dataset: Dataset, page_title=False) -> ReturnType: +def Go_To_Link(dataset: Dataset) -> ReturnType: try: sModuleInfo = inspect.currentframe().f_code.co_name + " : " + MODULE_NAME window_size_X = None @@ -867,6 +803,7 @@ def Go_To_Link(dataset: Dataset, page_title=False) -> ReturnType: raise ValueError("No dependency set - Cannot run") page_load_timeout_sec = 120 + web_link = None # None is for Open_Empty_Browser browser = options_map[dependency["Browser"]] driver_id = "" for left, mid, right in dataset: @@ -943,13 +880,15 @@ def Go_To_Link(dataset: Dataset, page_title=False) -> ReturnType: # Open URL in browser try: - try: - selenium_driver.get(web_link) - except TimeoutException as e: - CommonUtil.ExecLog(sModuleInfo, "Maximum page load time reached. Loading and proceeding", 2) + if web_link is not None: + try: + selenium_driver.get(web_link) + except TimeoutException as e: + CommonUtil.ExecLog(sModuleInfo, "Maximum page load time reached. Loading and proceeding", 2) - selenium_driver.implicitly_wait(0.5) # Wait for page to load - CommonUtil.ExecLog(sModuleInfo, "Successfully opened your link with driver_id='%s': %s" % (driver_id, web_link), 1) + selenium_driver.implicitly_wait(0.5) # Wait for page to load + CommonUtil.ExecLog(sModuleInfo, "Successfully opened your link with driver_id='%s': %s" % (driver_id, web_link), 1) + except WebDriverException as e: browser = selenium_driver.capabilities["browserName"].strip().lower() if (browser in ("chrome", "edge") and e.msg.lower().startswith("chrome not reachable")) or (browser == "firefox" and e.msg.lower().startswith("tried to run command without establishing a connection")): From cca8480ead3e7b333eddd6ec8d37889740f8f61c Mon Sep 17 00:00:00 2001 From: test Date: Mon, 14 Oct 2024 09:57:00 +0600 Subject: [PATCH 12/14] browser value fix --- .../Web/Selenium/BuiltInFunctions.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py index 8c6f99d5d..248914404 100644 --- a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py +++ b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py @@ -804,7 +804,10 @@ def Go_To_Link(dataset: Dataset) -> ReturnType: page_load_timeout_sec = 120 web_link = None # None is for Open_Empty_Browser - browser = options_map[dependency["Browser"]] + if dependency["Browser"] in options_map: + browser = options_map[dependency["Browser"]] + else: + browser = None driver_id = "" for left, mid, right in dataset: left = left.replace(" ", "").replace("_", "").replace("-", "").lower() @@ -826,9 +829,11 @@ def Go_To_Link(dataset: Dataset) -> ReturnType: browser_options["capabilities"] = CommonUtil.parse_value_into_object(right) # Options are browser specific. elif ( - mid.strip().lower() == "chromium option" and - browser in ("chrome", "edge") or - browser == mid.split(" ")[0].strip().lower() + browser is not None and ( + mid.strip().lower() == "chromium option" and + browser in ("chrome", "edge") or + browser == mid.split(" ")[0].strip().lower() + ) ): if left == "addargument": browser_options[browser]["add_argument"] = parse_and_verify_datatype(left, right) From 9451793fb66767d36e732f53f2b6fb26b7715219 Mon Sep 17 00:00:00 2001 From: test Date: Mon, 14 Oct 2024 12:44:39 +0600 Subject: [PATCH 13/14] remote-debugging enabled --- .../Web/Selenium/BuiltInFunctions.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py index 248914404..8db8f6670 100644 --- a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py +++ b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py @@ -508,6 +508,8 @@ def generate_options(browser: str, browser_options:BrowserOptions): options.add_encoded_extension(extension) if "page_load_strategy" in browser_options[b]: options.page_load_strategy = browser_options[b]["page_load_strategy"] + if "debugger_address" in browser_options[b]: + options.debugger_address = browser_options[b]["debugger_address"] msg += ( f"Experimental_options: {json.dumps(options.experimental_options, indent=2)}\n" f"Extensions: {json.dumps(options.extensions, indent=2)}\n" @@ -532,7 +534,8 @@ def generate_options(browser: str, browser_options:BrowserOptions): if "page_load_strategy" in browser_options["safari"]: options.page_load_strategy = browser_options["safari"]["page_load_strategy"] else: - raise Exception + from selenium.webdriver.common.options import ArgOptions + return ArgOptions() if "headless" in browser: def headless(): @@ -847,6 +850,8 @@ def Go_To_Link(dataset: Dataset) -> ReturnType: browser_options[browser]["set_preference"] = parse_and_verify_datatype(left, right) elif left == "pageloadstrategy": browser_options[browser]["page_load_strategy"] = right.strip() + elif left == "debugger_address": + browser_options[browser]["debugger_address"] = right.strip() if not driver_id: if len(selenium_details.keys()) == 0: @@ -860,16 +865,15 @@ def Go_To_Link(dataset: Dataset) -> ReturnType: if driver_id in selenium_details and selenium_details[driver_id]["driver"].capabilities["browserName"].strip().lower() != browser_map[dependency["Browser"]]: Tear_Down_Selenium() # If dependency is changed then teardown and relaunch selenium driver CommonUtil.ExecLog(sModuleInfo, "Browser not previously opened, doing so now", 1) - result = Open_Browser(dependency["Browser"], browser_options) + + if Open_Browser(dependency["Browser"], browser_options) == "zeuz_failed": + return "zeuz_failed" if not window_size_X and not window_size_Y: selenium_driver.maximize_window() else: selenium_driver.set_window_size(window_size_X, window_size_Y) - if result == "zeuz_failed": - return "zeuz_failed" - selenium_details[driver_id] = {"driver": Shared_Resources.Get_Shared_Variables("selenium_driver")} else: From e68ef45fa4ba309f0d9335eda99e31711d2c1038 Mon Sep 17 00:00:00 2001 From: Muntasib-creator Date: Mon, 14 Oct 2024 23:23:58 +0600 Subject: [PATCH 14/14] debugger_address and preferences fix --- .../Web/Selenium/BuiltInFunctions.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py index 8db8f6670..769b908a4 100644 --- a/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py +++ b/Framework/Built_In_Automation/Web/Selenium/BuiltInFunctions.py @@ -509,7 +509,10 @@ def generate_options(browser: str, browser_options:BrowserOptions): if "page_load_strategy" in browser_options[b]: options.page_load_strategy = browser_options[b]["page_load_strategy"] if "debugger_address" in browser_options[b]: + # When debugger_address is mentioned, the Service() object should be ignored by default + # Users need to remove experimental options by setting it to {} options.debugger_address = browser_options[b]["debugger_address"] + msg += f"Debugger address: {options.debugger_address}\n" msg += ( f"Experimental_options: {json.dumps(options.experimental_options, indent=2)}\n" f"Extensions: {json.dumps(options.extensions, indent=2)}\n" @@ -559,14 +562,15 @@ def headless(): msg += ( f"Capabilities: {json.dumps(options.capabilities, indent=2)}\n" + - f"Arguments: {json.dumps(options.arguments, indent=2)}\n" + f"Arguments: {json.dumps(options.arguments, indent=2)}\n" + + f"Page load strategy: {options.page_load_strategy}\n" ) CommonUtil.ExecLog(sModuleInfo, msg, 5) return options @logger def Open_Browser(browser, browser_options: BrowserOptions): - """ Launch browser and create instance """ + """ Launch browser from options and service object """ try: global selenium_driver sModuleInfo = inspect.currentframe().f_code.co_name + " : " + MODULE_NAME @@ -740,7 +744,12 @@ def parse_and_verify_datatype(left:str, right:str): if isinstance(val, dict): return val raise ValueError('Experimental_option must be dictionary. Example: {"mobileEmulation":{"deviceName": "Pixel 2 XL"}}') - + + elif left == "setpreference": + if isinstance(val, dict): + return val + raise ValueError('Preference must be dictionary. Example: {"security.mixed_content.block_active_content": False}') + @logger def Go_To_Link(dataset: Dataset) -> ReturnType: try: @@ -850,7 +859,7 @@ def Go_To_Link(dataset: Dataset) -> ReturnType: browser_options[browser]["set_preference"] = parse_and_verify_datatype(left, right) elif left == "pageloadstrategy": browser_options[browser]["page_load_strategy"] = right.strip() - elif left == "debugger_address": + elif left == "debuggeraddress": browser_options[browser]["debugger_address"] = right.strip() if not driver_id: