diff --git a/script/code_generator/search_class_model.py b/script/code_generator/search_class_model.py index 6289189..b008eb4 100755 --- a/script/code_generator/search_class_model.py +++ b/script/code_generator/search_class_model.py @@ -166,7 +166,8 @@ def fill_search_field(ast_obj, var_name="", py_filename=""): # default=uuid.uuid4().hex _logger.warning( f"Cannot support keyword of variable {var_name} type" - f" {ast_obj_type} in filename {py_filename}, because parent_node is type ast.Call." + f" {ast_obj_type} in filename {py_filename}, because" + " parent_node is type ast.Call." ) elif ast_obj_type is ast.List: result = [fill_search_field(a, var_name) for a in ast_obj.elts] diff --git a/script/selenium/README.md b/script/selenium/README.md new file mode 100644 index 0000000..6808a83 --- /dev/null +++ b/script/selenium/README.md @@ -0,0 +1,3 @@ +# Installation Ubuntu 20.04 + + sudo apt install libcairo2-dev diff --git a/script/selenium/requirements.txt b/script/selenium/requirements.txt new file mode 100644 index 0000000..1928b4e --- /dev/null +++ b/script/selenium/requirements.txt @@ -0,0 +1,5 @@ +# Selenium video +PyGObject==3.44.1 +gst +# python-vlc +python-randomword-fr diff --git a/script/selenium/selenium_devops.py b/script/selenium/selenium_devops.py new file mode 100755 index 0000000..730eb9f --- /dev/null +++ b/script/selenium/selenium_devops.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 +import sys +import argparse +import web_login +import selenium_lib + + +def run(config, selenium_tool): + if config.open_me_devops: + selenium_tool.click( + "/html/body/header/nav/div/div[1]/div[2]/div/div/div/ul/li[2]/a", + ) + selenium_tool.click( + "/html/body/div[1]/main/div[2]/div/div/table/tbody/tr[1]/td[2]", + ) + if config.open_me_devops_auto: + selenium_tool.click( + "/html/body/header/nav/div/div[1]/div[2]/div/div/div/ul/li[2]/a", + ) + selenium_tool.click( + "/html/body/div[1]/main/div[2]/div/div/table/tbody/tr[1]/td[2]", + ) + + # CG self + # Bouton modifier + # selenium_tool.click( + # "/html/body/div[1]/main/div[1]/div[2]/div/div/div[1]/button[1]", + # ) + # Tab Code + # selenium_tool.click( + # "/html/body/div[1]/main/div[2]/div/div/div[7]/ul/li[2]/a", + # ) + # Bouton Plan + selenium_tool.click( + "/html/body/div[1]/main/div[2]/div/div/div[1]/div/button[1]", + ) + + # Bouton autopoiesis + selenium_tool.click( + "/html/body/div[4]/div/div/main/div/div/div[5]/table[2]/tbody/tr[2]/td[1]/button", + ) + + # Bouton devops regenerate + selenium_tool.click( + "/html/body/div[4]/div/div/main/div/div/div[6]/table[2]/tbody/tr[2]/td/button", + ) + + if config.open_me_devops_auto_force: + # Disable «Stop Execution if Env Not Clean + # selenium_tool.click( + # "/html/body/div[1]/main/div[2]/div/div/div[7]/div/div[2]/div[6]/table[2]/tbody/tr[3]/td[2]/div/label", + # ) + # Option Force Generate + selenium_tool.click( + "/html/body/div[4]/div/div/main/div/div/div[8]/table/tbody/tr[2]/td[1]/label", + ) + + # Gen + # selenium_tool.click( + # "/html/body/div[1]/main/div[2]/div/div/div[7]/div/div[2]/div[2]/table[1]/tbody/tr/td[1]/button", + # ) + + # Next state + selenium_tool.click( + "/html/body/div[4]/div/div/footer/div/footer/div/button[1]", + ) + + # Check error + # selenium_tool.click( + # "/html/body/div[1]/main/div[2]/div/div/div[7]/ul/li[13]/a", + # ) + # selenium_tool.click("/html/body/div[1]/main/div[2]/div/div/div[6]/div/div[14]/div/div[2]/table/tbody/tr[1]", timeout=60*2) + + +def fill_parser(parser): + group_devops = parser.add_argument_group(title="DevOps") + group_devops.add_argument( + "--open_me_devops", + action="store_true", + help="Open application devops and show entry me.", + ) + group_devops.add_argument( + "--open_me_devops_auto", + action="store_true", + help="Open application devops and show entry me and run auto setup.", + ) + group_devops.add_argument( + "--open_me_devops_auto_force", + action="store_true", + help=( + "Open application devops and show entry me and run auto setup with" + " forcing argument." + ), + ) + + +def compute_args(args): + if args.open_me_devops_auto_force: + args.open_me_devops_auto = True + args.open_me_devops = True + elif args.open_me_devops_auto: + args.open_me_devops = True + + +def main(): + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description="""Selenium script to open web browser to ERPLibre adapted for ORE.""", + ) + # Generate parser + selenium_lib.fill_parser(parser) + web_login.fill_parser(parser) + fill_parser(parser) + args = parser.parse_args() + web_login.compute_args(args) + compute_args(args) + # Instance selenium tool + selenium_tool = selenium_lib.SeleniumLib(args) + selenium_tool.configure() + selenium_tool.start_record() + # Execute + web_login.run(args, selenium_tool) + run(args, selenium_tool) + selenium_tool.stop_record() + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/script/selenium/selenium_lib.py b/script/selenium/selenium_lib.py new file mode 100644 index 0000000..f366735 --- /dev/null +++ b/script/selenium/selenium_lib.py @@ -0,0 +1,450 @@ +#!/usr/bin/env python3 +from randomwordfr import RandomWordFr +import re +import os +import sys +import time +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.firefox.service import Service +from subprocess import getoutput +from selenium.webdriver import ActionChains +from selenium.webdriver.common.actions.wheel_input import ScrollOrigin + + +class SeleniumLib(object): + def __init__(self, config): + self.config = config + self.video_recorder = None + self.filename = "video_" + time.strftime("%Y_%m_%d-%H_%M_%S") + ".webm" + self.driver = None + + def configure(self): + # Configuration pour lancer Firefox en mode de navigation privée + firefox_options = webdriver.FirefoxOptions() + if not self.config.not_private_mode: + firefox_options.add_argument("--private") + + # firefox_options.set_preference("browser.link.open_newwindow", 3) + # firefox_options.set_preference("browser.link.open_newwindow.restriction", 2) + + # Définissez la préférence pour les notifications de bureau + # 1 signifie "autoriser", 2 signifie "bloquer" + firefox_options.set_preference( + "permissions.default.desktop-notification", 1 + ) + firefox_services = None + if self.config.firefox_binary_path: + firefox_services = Service( + executable_path=self.config.firefox_binary_path + ) + if self.config.gecko_binary_path: + firefox_options.binary_location = self.config.gecko_binary_path + + # Créez une instance du navigateur Firefox avec les options de navigation privée + try: + self.driver = webdriver.Firefox( + options=firefox_options, service=firefox_services + ) + except Exception: + print( + "Cannot open Firefox profile, so will force firefox snap for" + " Ubuntu users." + ) + firefox_services = Service( + executable_path=getoutput( + "find /snap/firefox -name geckodriver" + ).split("\n")[-1] + ) + firefox_options.binary_location = getoutput( + "find /snap/firefox -name firefox" + ).split("\n")[-1] + self.driver = webdriver.Firefox( + options=firefox_options, service=firefox_services + ) + + # Ajout de l'enregistrement + if self.config.record_mode: + new_path = os.path.normpath( + os.path.join(os.path.dirname(__file__), "..", "..") + ) + sys.path.append(new_path) + from script.selenium.selenium_video import VideoRecorder + + self.video_recorder = VideoRecorder( + self.driver, filename=self.filename + ) + # import vlc + + # Install DarkReader to help my eyes + # TODO do a script to check if it's the last version + if not self.config.no_dark_mode: + self.driver.install_addon( + "./script/selenium/darkreader-firefox.xpi", temporary=True + ) + self.driver.install_addon( + "./script/selenium/odoo_debug-4.0.xpi", temporary=True + ) + + if not self.config.not_private_mode and not self.config.no_dark_mode: + self.driver.get("about:addons") + # Enable Dark Reader into incognito + self.click("/html/body/div/div[1]/categories-box/button[2]") + self.click( + "/html/body/div/div[2]/div/addon-list/section[1]/addon-card/div/div/div/div/button", + ) + self.click( + "/html/body/div/div[2]/div/addon-list/section[1]/addon-card/div/addon-options/panel-list/panel-item[5]", + ) + self.click( + "/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[5]/div/label[1]/input", + ) + + # Enable Odoo_debug into incognito + # Back + self.click( + "/html/body/div/div[2]/addon-page-header/div/div[2]/button" + ) + self.click( + "/html/body/div/div[2]/div/addon-list/section[1]/addon-card[2]/div/div/div/div/button", + ) + self.click( + "/html/body/div/div[2]/div/addon-list/section[1]/addon-card[2]/div/addon-options/panel-list/panel-item[5]", + ) + self.click( + "/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[5]/div/label[1]/input", + ) + + # Ouvrez la page web + self.driver.get(f"{self.config.url}/web") + + # Close tab opening by DarkReader + if self.config.not_private_mode and not self.config.no_dark_mode: + self.driver.switch_to.window(self.driver.window_handles[-1]) + self.driver.close() + self.driver.switch_to.window(self.driver.window_handles[0]) + + @staticmethod + def get_french_word_no_space_no_accent(): + word = "" + rw = RandomWordFr() + while not word or " " in word: + word = rw.get().get("word") + if not re.match("^[a-zA-Z_]+$", word): + word = "" + return word + + def click(self, xpath, timeout=5): + wait = WebDriverWait(self.driver, timeout) + button = wait.until( + EC.element_to_be_clickable( + ( + By.XPATH, + xpath, + ) + ) + ) + button.click() + + def get_element(self, by: str = By.ID, value: str = None, timeout=5): + wait = WebDriverWait(self.driver, timeout) + ele = wait.until( + EC.visibility_of_any_elements_located( + ( + by, + value, + ) + ) + ) + + return ele[0] + + def click_with_mouse_move( + self, + by: str = By.ID, + value: str = None, + timeout: int = 5, + no_scroll: bool = False, + viewport_ele_by: str = By.ID, + viewport_ele_value: str = None, + ): + # ele = self.driver.find_element(by, value) + ele = self.get_element(by, value, timeout) + if not no_scroll: + viewport_ele = None + if viewport_ele_value: + viewport_ele = self.get_element( + viewport_ele_by, viewport_ele_value, timeout + ) + self.scrollto_element(ele, viewport_ele=viewport_ele) + ActionChains(self.driver).move_to_element(ele).perform() + time.sleep(self.config.selenium_default_delay) + wait = WebDriverWait(self.driver, timeout) + button = wait.until( + EC.element_to_be_clickable( + ( + by, + value, + ) + ) + ) + button.click() + + def input_text_with_mouse_move( + self, + by: str = By.ID, + value: str = None, + text_value: str = "", + delay_after: int = -1, + timeout: int = 5, + no_scroll: bool = False, + viewport_ele_by: str = By.ID, + viewport_ele_value: str = None, + ): + # ele = self.driver.find_element(by, value) + ele = self.get_element(by, value) + if not no_scroll: + viewport_ele = None + if viewport_ele_value: + viewport_ele = self.get_element( + viewport_ele_by, viewport_ele_value, timeout + ) + self.scrollto_element(ele, viewport_ele=viewport_ele) + ActionChains(self.driver).move_to_element(ele).perform() + ele.send_keys(text_value) + if delay_after > 0: + time.sleep(delay_after) + elif self.config.selenium_default_delay > 0: + time.sleep(self.config.selenium_default_delay) + + def scrollto_element1(self, element_name): + # ele = self.driver.find_element(By.TAG_NAME, element_name) + ele = self.get_element(By.TAG_NAME, element_name) + # delta_y = ele.rect["y"] + ActionChains(self.driver).scroll_to_element(ele).perform() + # ele = self.get_element(By.TAG_NAME, element_name) + # delta_y = ele.rect["y"] + # ActionChains(self.driver).scroll_by_amount(0, delta_y).perform() + time.sleep(0.5) + + def scrollto_xpath5(self, xpath): + footer = self.driver.find_element(By.XPATH, xpath) + # footer = self.get_element(By.XPATH, xpath) + delta_y = footer.rect["y"] + ActionChains(self.driver).scroll_by_amount(0, int(delta_y)).perform() + time.sleep(0.5) + + def scrollto_xpath2(self, xpath): + footer = self.driver.find_element(By.XPATH, xpath) + # footer = self.get_element(By.XPATH, xpath) + scroll_origin = ScrollOrigin.from_element(footer) + ActionChains(self.driver).scroll_from_origin( + scroll_origin, 0, 100 + ).perform() + time.sleep(0.5) + + def scrollto_xpath3(self, xpath): + footer = self.driver.find_element(By.XPATH, xpath) + # footer = self.get_element(By.XPATH, xpath) + scroll_origin = ScrollOrigin.from_element(footer) + ActionChains(self.driver).scroll_to_element(scroll_origin).perform() + time.sleep(0.5) + + def scrollto_xpath( + self, + xpath, + offset_middle=True, + smooth_scroll=True, + smooth_speed=50, + smooth_fps=1 / 25, + ): + footer = self.driver.find_element(By.XPATH, xpath) + # footer = self.get_element(By.XPATH, xpath) + scroll_origin = ScrollOrigin.from_viewport(10, 10) + delta_y = footer.rect["y"] + if offset_middle: + # TODO check size windows and divide by 2 + delta_y -= 400 + print(f"scroll to xpath at y:{delta_y} position") + if smooth_scroll: + actual_pos = 0 + while delta_y > actual_pos: + actual_pos += smooth_speed + print(actual_pos) + ActionChains(self.driver).scroll_from_origin( + scroll_origin, 0, int(smooth_speed) + ).perform() + print(f"Wait {smooth_fps} seconds") + time.sleep(smooth_fps) + print("end") + else: + ActionChains(self.driver).scroll_from_origin( + scroll_origin, 0, int(delta_y) + ).perform() + + time.sleep(0.5) + + def scrollto_element( + self, + element, + offset_middle=True, + smooth_scroll=True, + smooth_speed=50, + smooth_fps=1 / 25, + viewport_ele=None, + ): + if viewport_ele: + scroll_origin = ScrollOrigin.from_element(viewport_ele, 10, 10) + else: + scroll_origin = ScrollOrigin.from_viewport(10, 10) + delta_y = element.rect["y"] + if offset_middle: + # TODO check size windows and divide by 2 + delta_y -= 400 + print(f"scroll to xpath at y:{delta_y} position") + if smooth_scroll: + actual_pos = 0 + while delta_y > actual_pos: + actual_pos += smooth_speed + print(actual_pos) + ActionChains(self.driver).scroll_from_origin( + scroll_origin, 0, int(smooth_speed) + ).perform() + print(f"Wait {smooth_fps} seconds") + time.sleep(smooth_fps) + print("end") + else: + ActionChains(self.driver).scroll_from_origin( + scroll_origin, 0, int(delta_y) + ).perform() + + # action = ActionChains(self.driver) + # action.click_and_hold(element).move_by_offset(0, 1).perform() + # # Don't forget to release the click_and_hold, for example with: + # action.reset_actions() + time.sleep(0.5) + + def inject_cursor(self): + cursor_script = """ + var cursor = document.createElement('div'); + cursor.style.position = 'absolute'; + cursor.style.zIndex = '9999'; + cursor.style.width = '30px'; + cursor.style.height = '30px'; + cursor.style.borderRadius = '50%'; + cursor.style.backgroundColor = 'red'; + cursor.style.pointerEvents = 'none'; + document.body.appendChild(cursor); + + document.addEventListener('mousemove', function(e) { + cursor.style.left = e.pageX - 5 + 'px'; + cursor.style.top = e.pageY - 5 + 'px'; + }); + """ + self.driver.execute_script(cursor_script) + + def open_tab(self, url): + # Open a new window + self.driver.execute_script("window.open('');") + # Switch to the new window and open new URL + self.driver.switch_to.window(self.driver.window_handles[1]) + self.driver.get(url) + + def check_bot_chat_and_close(self): + try: + xpath_button = "/html/body/div[3]/div[1]/span[2]/a[2]" + button = self.driver.find_element(By.XPATH, xpath_button) + # button = self.get_element(By.XPATH, xpath_button) + self.click(self.driver, xpath_button) + except Exception: + print("Chatbot cannot be found, stop searching it.") + + def start_record(self): + # Démarrer l'enregistrement + if self.config.record_mode: + self.video_recorder.start() + + def stop_record(self): + time.sleep(self.config.selenium_default_delay_presentation) + + # Arrêter l'enregistrement + if self.config.record_mode: + time.sleep(self.config.selenium_video_time_waiting_end) + self.video_recorder.stop() + print("End of recording video") + + if self.config.selenium_video_auto_play_video: + print(f"Play video {self.filename}") + # By python-vlc + # media_player = vlc.MediaPlayer(filename) + # media = vlc.Media(filename) + # media_player.set_media(media) + # media_player.play() + # time.sleep(15) + # By external process + os.popen(f"vlc {self.filename}") + + +def fill_parser(parser): + parser.add_argument( + "--url", + default="http://127.0.0.1:8069", + help="First URL to open.", + ) + + group_animation = parser.add_argument_group(title="Animation") + group_animation.add_argument( + "--selenium_default_delay", + default=0.4, + type=float, + help="Pause at the end before close video.", + ) + + group_browser = parser.add_argument_group(title="Browser") + group_browser.add_argument( + "--not_private_mode", + action="store_true", + help="Default is private mode.", + ) + group_browser.add_argument( + "--no_dark_mode", + action="store_true", + help=( + "By default, will be in dark mode, because the main developer" + " like it!" + ), + ) + group_browser.add_argument( + "--firefox_binary_path", + help="Can specify firefox path to open selenium.", + ) + group_browser.add_argument( + "--gecko_binary_path", + help="Can specify firefox path to open selenium.", + ) + + group_record = parser.add_argument_group(title="Recording") + group_record.add_argument( + "--record_mode", + action="store_true", + help="Start recording (not finish to be implemented).", + ) + group_record.add_argument( + "--selenium_video_time_waiting_end", + default=5, + type=int, + help="Pause at the end before close video.", + ) + group_record.add_argument( + "--selenium_default_delay_presentation", + default=2, + type=float, + help="Pause at the end before close video.", + ) + group_record.add_argument( + "--selenium_video_auto_play_video", + action="store_true", + help="Autoplay the video when done.", + ) diff --git a/script/selenium/web_login.py b/script/selenium/web_login.py index ea297e1..9d013fe 100755 --- a/script/selenium/web_login.py +++ b/script/selenium/web_login.py @@ -5,242 +5,80 @@ import os import sys import time -from selenium import webdriver +import selenium_lib + from selenium.webdriver.common.by import By -from selenium.webdriver.support import expected_conditions as EC -from selenium.webdriver.support.ui import WebDriverWait -from selenium.common.exceptions import NoSuchElementException -from selenium.webdriver.firefox.service import Service -from subprocess import getoutput -def get_config(): - parser = argparse.ArgumentParser( - formatter_class=argparse.RawDescriptionHelpFormatter, - description="""Selenium script to open web browser to ERPLibre.""", - epilog="""\ -""", - ) - parser.add_argument( - "--open_me_devops", - action="store_true", - help="Open application devops and show entry me.", - ) - parser.add_argument( - "--open_me_devops_auto", - action="store_true", - help="Open application devops and show entry me and run auto setup.", - ) - parser.add_argument( - "--open_me_devops_auto_force", - action="store_true", - help=( - "Open application devops and show entry me and run auto setup with" - " forcing argument." - ), - ) - parser.add_argument( +def fill_parser(parser): + group_login = parser.add_argument_group(title="Login") + group_login.add_argument( "--open_dashboard", action="store_true", help="Open application Board.", ) - parser.add_argument( - "--not_private_mode", - action="store_true", - help="Default is private mode.", + group_login.add_argument( + "--default_email_auth", + default="admin", + help="Email to use to authenticate with admin.", ) - parser.add_argument( - "--record_mode", - action="store_true", - help="Start recording (not finish to be implemented).", + group_login.add_argument( + "--default_password_auth", + default="admin", + help="Password to use to authenticate with admin.", ) - parser.add_argument( - "--not_dark_mode", - action="store_true", - help=( - "By default, will be in dark mode, because the main developer" - " like it!" - ), - ) - parser.add_argument( - "--firefox_binary_path", - help="Can specify firefox path to open selenium.", - ) - parser.add_argument( - "--gecko_binary_path", - help="Can specify firefox path to open selenium.", - ) - parser.add_argument( - "--url", - default="http://127.0.0.1:8069", - help="URL to open.", - ) - args = parser.parse_args() - if args.open_me_devops_auto_force: - args.open_me_devops_auto = True - args.open_me_devops = True - elif args.open_me_devops_auto: - args.open_me_devops = True - return args -def click(driver, xpath, time=5): - wait = WebDriverWait(driver, time) - button = wait.until( - EC.element_to_be_clickable( - ( - By.XPATH, - xpath, - ) - ) - ) - button.click() - - -def check_bot_chat_and_close(driver): - try: - xpath_button = "/html/body/div[3]/div[1]/span[2]/a[2]" - button = driver.find_element(By.XPATH, xpath_button) - click(driver, xpath_button) - except Exception: - print("Chatbot cannot be found, stop searching it.") - - -def run(config): - if config.record_mode: - new_path = os.path.normpath( - os.path.join(os.path.dirname(__file__), "..", "..") - ) - sys.path.append(new_path) - from script.selenium.selenium_video import VideoRecorder - - # Configuration pour lancer Firefox en mode de navigation privée - firefox_options = webdriver.FirefoxOptions() - if not config.not_private_mode: - firefox_options.add_argument("--private") - - # Définissez la préférence pour les notifications de bureau - # 1 signifie "autoriser", 2 signifie "bloquer" - firefox_options.set_preference( - "permissions.default.desktop-notification", 1 - ) - firefox_services = None - if config.firefox_binary_path: - firefox_services = Service(executable_path=config.firefox_binary_path) - if config.gecko_binary_path: - firefox_options.binary_location = config.gecko_binary_path - - # Créez une instance du navigateur Firefox avec les options de navigation privée - try: - driver = webdriver.Firefox( - options=firefox_options, service=firefox_services - ) - except Exception: - print( - "Cannot open Firefox profile, so will force firefox snap for" - " Ubuntu users." - ) - firefox_services = Service( - executable_path=getoutput( - "find /snap/firefox -name geckodriver" - ).split("\n")[-1] - ) - firefox_options.binary_location = getoutput( - "find /snap/firefox -name firefox" - ).split("\n")[-1] - driver = webdriver.Firefox( - options=firefox_options, service=firefox_services - ) - - # Ajout de l'enregistrement - if config.record_mode: - video_recorder = VideoRecorder(driver) - else: - video_recorder = None - - # Install DarkReader to help my eyes - # TODO do a script to check if it's the last version - if not config.not_dark_mode: - driver.install_addon( - "./script/selenium/darkreader-firefox.xpi", temporary=True - ) - driver.install_addon( - "./script/selenium/odoo_debug-4.0.xpi", temporary=True - ) - - if not config.not_private_mode and not config.not_dark_mode: - driver.get("about:addons") - # Enable Dark Reader into incognito - click(driver, "/html/body/div/div[1]/categories-box/button[2]") - click( - driver, - "/html/body/div/div[2]/div/addon-list/section[1]/addon-card/div/div/div/div/button", - ) - click( - driver, - "/html/body/div/div[2]/div/addon-list/section[1]/addon-card/div/addon-options/panel-list/panel-item[5]", - ) - click( - driver, - "/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[5]/div/label[1]/input", - ) - - # Enable Odoo_debug into incognito - # Back - click( - driver, "/html/body/div/div[2]/addon-page-header/div/div[2]/button" - ) - click( - driver, - "/html/body/div/div[2]/div/addon-list/section[1]/addon-card[2]/div/div/div/div/button", - ) - click( - driver, - "/html/body/div/div[2]/div/addon-list/section[1]/addon-card[2]/div/addon-options/panel-list/panel-item[5]", - ) - click( - driver, - "/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[5]/div/label[1]/input", - ) - - # Ouvrez la page web - driver.get(f"{config.url}/web") - - # Close tab opening by DarkReader - if config.not_private_mode and not config.not_dark_mode: - driver.switch_to.window(driver.window_handles[-1]) - driver.close() - driver.switch_to.window(driver.window_handles[0]) - - # Démarrer l'enregistrement - if config.record_mode: - video_recorder.start() - +def run(config, selenium_tool): # Trouvez les éléments du formulaire - courriel_input = driver.find_element(By.NAME, "login") - mot_de_passe_input = driver.find_element(By.NAME, "password") + courriel_input = selenium_tool.driver.find_element(By.NAME, "login") + mot_de_passe_input = selenium_tool.driver.find_element(By.NAME, "password") try: - connexion_button = driver.find_element( + connexion_button = selenium_tool.driver.find_element( By.XPATH, "/html/body/div/div/div/form/div[3]/button" # '//button[contains(text(), "Log in")]' ) except Exception: - connexion_button = driver.find_element( + connexion_button = selenium_tool.driver.find_element( By.XPATH, "/html/body/div/main/div/form/div[3]/button" # '//button[contains(text(), "Connexion")]' ) # Remplissez le courriel et le mot de passe - courriel_input.send_keys("admin") - mot_de_passe_input.send_keys("admin") + courriel_input.send_keys(config.default_email_auth) + mot_de_passe_input.send_keys(config.default_password_auth) # Cliquez sur le bouton "Connexion" - connexion_button.click() + try: + connexion_button.click() + except Exception as e: + if ( + 'class="modal o_technical_modal show modal_shown"> obscures it' + in str(e) + ): + # Click it + # xpath_button = "//div[hasclass('o_technical_modal')]/div/div/footer/button" + xpath_button = ( + "//div[contains(@class," + " 'o_technical_modal')]/div/div/footer/button" + ) + error_button = selenium_tool.driver.find_element( + By.XPATH, xpath_button + ) + error_button.click() + + # Remplissez le courriel et le mot de passe + courriel_input.send_keys(config.default_email_auth) + mot_de_passe_input.send_keys(config.default_password_auth) + + connexion_button.click() + else: + raise e # Attendez que l'élément soit cliquable - # wait = WebDriverWait(driver, 5) + # wait = WebDriverWait(selenium_tool.driver, 5) # menu_toggle = wait.until( # EC.element_to_be_clickable((By.XPATH, "/html/body/header/nav/ul[1]/li/a")) # ) @@ -259,112 +97,49 @@ def run(config): # ) # Remove chatbot if open, because will crash wizard div[4] (to div[5]) - check_bot_chat_and_close(driver) + selenium_tool.check_bot_chat_and_close() # Open View - if config.open_me_devops: - click( - driver, - "/html/body/header/nav/div/div[1]/div[2]/div/div/div/ul/li[2]/a", - ) - click( - driver, - "/html/body/div[1]/main/div[2]/div/div/table/tbody/tr[1]/td[2]", - ) - if config.open_me_devops_auto: - click( - driver, - "/html/body/header/nav/div/div[1]/div[2]/div/div/div/ul/li[2]/a", - ) - click( - driver, - "/html/body/div[1]/main/div[2]/div/div/table/tbody/tr[1]/td[2]", - ) - - # CG self - # Bouton modifier - # click( - # driver, - # "/html/body/div[1]/main/div[1]/div[2]/div/div/div[1]/button[1]", - # ) - # Tab Code - # click( - # driver, - # "/html/body/div[1]/main/div[2]/div/div/div[7]/ul/li[2]/a", - # ) - # Bouton Plan - click( - driver, - "/html/body/div[1]/main/div[2]/div/div/div[1]/div/button[1]", - ) - - # Bouton autopoiesis - click( - driver, - "/html/body/div[4]/div/div/main/div/div/div[5]/table[2]/tbody/tr[2]/td[1]/button", - ) - - # Bouton devops regenerate - click( - driver, - "/html/body/div[4]/div/div/main/div/div/div[6]/table[2]/tbody/tr[2]/td/button", - ) - - if config.open_me_devops_auto_force: - # Disable «Stop Execution if Env Not Clean - # click( - # driver, - # "/html/body/div[1]/main/div[2]/div/div/div[7]/div/div[2]/div[6]/table[2]/tbody/tr[3]/td[2]/div/label", - # ) - # Option Force Generate - click( - driver, - "/html/body/div[4]/div/div/main/div/div/div[8]/table/tbody/tr[2]/td[1]/label", - ) - - # Gen - # click( - # driver, - # "/html/body/div[1]/main/div[2]/div/div/div[7]/div/div[2]/div[2]/table[1]/tbody/tr/td[1]/button", - # ) - - # Next state - click( - driver, - "/html/body/div[4]/div/div/footer/div/footer/div/button[1]", - ) - - # Check error - # click( - # driver, - # "/html/body/div[1]/main/div[2]/div/div/div[7]/ul/li[13]/a", - # ) - # click(driver, "/html/body/div[1]/main/div[2]/div/div/div[6]/div/div[14]/div/div[2]/table/tbody/tr[1]", time=60*2) - elif config.open_dashboard: - click( - driver, + if config.open_dashboard: + selenium_tool.click( "/html/body/header/nav/div/div[1]/div[2]/div/div/div/ul/li[3]/a", ) - # Arrêter l'enregistrement - if config.record_mode: - video_recorder.stop() - # Open conversation chat - # conversation_button = driver.find_element(By.XPATH, '/html/body/header/nav/ul[3]/li[2]/a') + # conversation_button = selenium_tool.driver.find_element(By.XPATH, '/html/body/header/nav/ul[3]/li[2]/a') # conversation_button.click() # Close bot chat - # conversation_button = driver.find_element(By.XPATH, '/html/body/div[3]/div[1]/span[2]/a[2]') + # conversation_button = selenium_tool.driver.find_element(By.XPATH, '/html/body/div[3]/div[1]/span[2]/a[2]') # conversation_button.click() # Fermez le navigateur - # driver.quit() + # selenium_tool.driver.quit() + + +def compute_args(args): + pass def main(): - config = get_config() - run(config) + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description="""Selenium script to open web browser to ERPLibre.""", + epilog="""\ + """, + ) + # Generate parser + selenium_lib.fill_parser(parser) + fill_parser(parser) + args = parser.parse_args() + compute_args(args) + # Instance selenium tool + selenium_tool = selenium_lib.SeleniumLib(args) + selenium_tool.configure() + selenium_tool.start_record() + # Execute + run(args, selenium_tool) + selenium_tool.stop_record() return 0