[UPD] script selenium better tools to navigate into Odoo
- support external selenium service to support selenium from Odoo instance - move selenium installation to erplibre virtual environment - support user test instead of admin
This commit is contained in:
parent
cbc43fde3c
commit
3d6b340b6d
3 changed files with 691 additions and 129 deletions
|
|
@ -3,19 +3,22 @@
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import getpass
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import time
|
|
||||||
import json
|
|
||||||
import tempfile
|
import tempfile
|
||||||
from subprocess import getoutput
|
import time
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
|
from subprocess import getoutput
|
||||||
from tkinter import filedialog
|
from tkinter import filedialog
|
||||||
import getpass
|
|
||||||
from pykeepass import PyKeePass
|
|
||||||
|
|
||||||
|
from pykeepass import PyKeePass
|
||||||
from randomwordfr import RandomWordFr
|
from randomwordfr import RandomWordFr
|
||||||
from selenium import webdriver
|
from selenium import webdriver
|
||||||
from selenium.common.exceptions import (
|
from selenium.common.exceptions import (
|
||||||
|
|
@ -30,17 +33,54 @@ from selenium.webdriver.firefox.options import Options
|
||||||
from selenium.webdriver.firefox.service import Service
|
from selenium.webdriver.firefox.service import Service
|
||||||
from selenium.webdriver.remote.webelement import WebElement
|
from selenium.webdriver.remote.webelement import WebElement
|
||||||
from selenium.webdriver.support import expected_conditions as EC
|
from selenium.webdriver.support import expected_conditions as EC
|
||||||
from selenium.webdriver.support.ui import WebDriverWait
|
from selenium.webdriver.support.ui import Select, WebDriverWait
|
||||||
|
|
||||||
|
from script.config import config_file
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
format=(
|
||||||
|
"%(asctime)s,%(msecs)d %(levelname)-8s [%(filename)s:%(lineno)d]"
|
||||||
|
" %(message)s"
|
||||||
|
),
|
||||||
|
datefmt="%Y-%m-%d:%H:%M:%S",
|
||||||
|
level=logging.INFO,
|
||||||
|
)
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# TODO maybe use TODO lib
|
# TODO maybe use TODO lib
|
||||||
CONFIG_FILE = "./script/todo/todo.json"
|
CONFIG_FILE = "./script/todo/todo.json"
|
||||||
CONFIG_OVERRIDE_FILE = "./private/todo.json"
|
CONFIG_OVERRIDE_FILE = "./private/todo/todo.json"
|
||||||
|
LOGO_ASCII_FILE = "./script/todo/logo_ascii.txt"
|
||||||
|
|
||||||
|
MONTHS_FR = {
|
||||||
|
"janvier": 1,
|
||||||
|
"février": 2,
|
||||||
|
"fevrier": 2,
|
||||||
|
"mars": 3,
|
||||||
|
"avril": 4,
|
||||||
|
"mai": 5,
|
||||||
|
"juin": 6,
|
||||||
|
"juillet": 7,
|
||||||
|
"août": 8,
|
||||||
|
"aout": 8,
|
||||||
|
"septembre": 9,
|
||||||
|
"octobre": 10,
|
||||||
|
"novembre": 11,
|
||||||
|
"décembre": 12,
|
||||||
|
"decembre": 12,
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO maybe use TODO lib
|
||||||
|
CONFIG_FILE = "./script/todo/todo.json"
|
||||||
|
CONFIG_OVERRIDE_FILE = "./private/todo/todo.json"
|
||||||
LOGO_ASCII_FILE = "./script/todo/logo_ascii.txt"
|
LOGO_ASCII_FILE = "./script/todo/logo_ascii.txt"
|
||||||
|
|
||||||
|
|
||||||
class SeleniumLib(object):
|
class SeleniumLib(object):
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
self.config = config
|
self.config = config
|
||||||
|
self.wait_human_time = config.human_time_speed
|
||||||
|
self.config_file = config_file.ConfigFile()
|
||||||
self.kdbx = None
|
self.kdbx = None
|
||||||
self.video_recorder = None
|
self.video_recorder = None
|
||||||
self.default_download_dir_path = tempfile.mkdtemp()
|
self.default_download_dir_path = tempfile.mkdtemp()
|
||||||
|
|
@ -60,8 +100,13 @@ class SeleniumLib(object):
|
||||||
)
|
)
|
||||||
self.dirname_recording = dir_path_screencast
|
self.dirname_recording = dir_path_screencast
|
||||||
self.driver = None
|
self.driver = None
|
||||||
with open(".odoo-version") as txt:
|
if os.path.isfile(".odoo-version"):
|
||||||
self.odoo_version = txt.read()
|
with open(".odoo-version") as txt:
|
||||||
|
self.odoo_version = txt.read()
|
||||||
|
else:
|
||||||
|
# Default version
|
||||||
|
# TODO instead, need to detect the version from client and detection
|
||||||
|
self.odoo_version = "18.0"
|
||||||
|
|
||||||
def do_screenshot(self):
|
def do_screenshot(self):
|
||||||
if self.config.scenario_screenshot:
|
if self.config.scenario_screenshot:
|
||||||
|
|
@ -113,25 +158,155 @@ class SeleniumLib(object):
|
||||||
|
|
||||||
# Créez une instance du navigateur Firefox avec les options de navigation privée
|
# Créez une instance du navigateur Firefox avec les options de navigation privée
|
||||||
try:
|
try:
|
||||||
self.driver = webdriver.Firefox(
|
user = os.environ.get("USER", "Non défini")
|
||||||
options=firefox_options, service=firefox_services
|
uid = os.getuid()
|
||||||
|
gid = os.getgid()
|
||||||
|
print(f"INFO: Execute by user: {user}, UID: {uid}, GID: {gid}")
|
||||||
|
|
||||||
|
# Exécuter la commande 'whoami' pour confirmation
|
||||||
|
whoami_result = subprocess.run(
|
||||||
|
["whoami"], capture_output=True, text=True
|
||||||
)
|
)
|
||||||
except Exception:
|
print(f"INFO: Result 'whoami': {whoami_result.stdout.strip()}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ERROR when check user: {e}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
if self.config.use_chrome_driver:
|
||||||
|
from selenium.webdriver.chrome.options import (
|
||||||
|
Options as ChromeOptions,
|
||||||
|
)
|
||||||
|
from selenium.webdriver.chrome.service import Service
|
||||||
|
|
||||||
|
chrome_options = ChromeOptions()
|
||||||
|
if self.config.window_size:
|
||||||
|
# chrome_options.add_argument("--window-size=1920,1080")
|
||||||
|
chrome_options.add_argument(
|
||||||
|
f"--window-size={self.config.window_size}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.config.use_network:
|
||||||
|
chrome_options.set_capability(
|
||||||
|
"se:name", "ERPLibre selenium"
|
||||||
|
)
|
||||||
|
self.driver = webdriver.Remote(
|
||||||
|
options=chrome_options,
|
||||||
|
command_executor=self.config.use_network,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
from webdriver_manager.chrome import ChromeDriverManager
|
||||||
|
|
||||||
|
service = Service(
|
||||||
|
ChromeDriverManager().install(),
|
||||||
|
log_path="/tmp/chromedriver.log",
|
||||||
|
)
|
||||||
|
self.driver = webdriver.Chrome(
|
||||||
|
options=chrome_options,
|
||||||
|
# options=firefox_options,
|
||||||
|
service=service,
|
||||||
|
keep_alive=True,
|
||||||
|
)
|
||||||
|
elif self.config.use_firefox_driver:
|
||||||
|
from selenium.webdriver.firefox.options import Options
|
||||||
|
from selenium.webdriver.firefox.service import Service
|
||||||
|
|
||||||
|
firefox_services = None
|
||||||
|
# shutil.which("geckodriver")
|
||||||
|
if self.config.gecko_binary_path:
|
||||||
|
firefox_services = Service(
|
||||||
|
executable_path=self.config.gecko_binary_path,
|
||||||
|
log_output=self.config.debug,
|
||||||
|
)
|
||||||
|
firefox_options = webdriver.FirefoxOptions()
|
||||||
|
if not self.config.not_private_mode:
|
||||||
|
firefox_options.add_argument("--private")
|
||||||
|
|
||||||
|
if self.config.firefox_binary_path:
|
||||||
|
firefox_options.binary_location = (
|
||||||
|
self.config.firefox_binary_path
|
||||||
|
)
|
||||||
|
elif not self.config.use_network:
|
||||||
|
status_location = subprocess.check_output(
|
||||||
|
["which", "firefox"], text=True
|
||||||
|
).strip()
|
||||||
|
firefox_options.binary_location = status_location
|
||||||
|
|
||||||
|
firefox_profile = webdriver.FirefoxProfile()
|
||||||
|
firefox_profile.set_preference(
|
||||||
|
"browser.cache.disk.enable", False
|
||||||
|
)
|
||||||
|
firefox_profile.set_preference(
|
||||||
|
"browser.cache.memory.enable", False
|
||||||
|
)
|
||||||
|
firefox_profile.set_preference(
|
||||||
|
"browser.cache.offline.enable", False
|
||||||
|
)
|
||||||
|
firefox_profile.set_preference("network.http.use-cache", False)
|
||||||
|
firefox_options.set_preference(
|
||||||
|
"permissions.default.desktop-notification", 1
|
||||||
|
)
|
||||||
|
firefox_options.set_preference(
|
||||||
|
"browser.download.folderList", 2
|
||||||
|
)
|
||||||
|
firefox_options.set_preference(
|
||||||
|
"browser.download.manager.showWhenStarting", False
|
||||||
|
)
|
||||||
|
firefox_options.set_preference(
|
||||||
|
"browser.download.dir", self.default_download_dir_path
|
||||||
|
)
|
||||||
|
firefox_options.set_preference(
|
||||||
|
"browser.helperApps.neverAsk.saveToDisk",
|
||||||
|
"application/octet-stream,application/pdf,application/x-pdf",
|
||||||
|
)
|
||||||
|
firefox_options.set_preference("pdfjs.disabled", True)
|
||||||
|
if self.config.window_size:
|
||||||
|
# chrome_options.add_argument("--window-size=1920,1080")
|
||||||
|
firefox_options.add_argument(
|
||||||
|
f"--window-size={self.config.window_size}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.config.headless:
|
||||||
|
firefox_options.add_argument("--headless")
|
||||||
|
# firefox_options.add_argument("--disable-gpu")
|
||||||
|
firefox_options.add_argument("--no-sandbox")
|
||||||
|
firefox_options.add_argument("--disable-dev-shm-usage")
|
||||||
|
firefox_options.add_argument("--disable-dbus")
|
||||||
|
|
||||||
|
if self.config.use_network:
|
||||||
|
firefox_options.set_capability(
|
||||||
|
"se:name", "ERPLibre selenium"
|
||||||
|
)
|
||||||
|
self.driver = webdriver.Remote(
|
||||||
|
options=firefox_options,
|
||||||
|
command_executor=self.config.use_network,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.driver = webdriver.Firefox(
|
||||||
|
options=firefox_options,
|
||||||
|
service=firefox_services,
|
||||||
|
keep_alive=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
print(
|
print(
|
||||||
"Cannot open Firefox profile, so will force firefox snap for"
|
"Cannot open Firefox profile, so will force firefox snap for"
|
||||||
" Ubuntu users."
|
" Ubuntu users."
|
||||||
)
|
)
|
||||||
firefox_services = Service(
|
# TODO au lieu, faire une recherche de geckodriver avant de démarrer
|
||||||
executable_path=getoutput(
|
# firefox_services = Service(
|
||||||
"find /snap/firefox -name geckodriver"
|
# executable_path=getoutput(
|
||||||
).split("\n")[-1]
|
# "find /snap/firefox -name geckodriver"
|
||||||
)
|
# ).split("\n")[-1], log_path='/tmp/geckodriver.log'
|
||||||
firefox_options.binary_location = getoutput(
|
# )
|
||||||
"find /snap/firefox -name firefox"
|
# firefox_options.binary_location = getoutput(
|
||||||
).split("\n")[-1]
|
# "find /snap/firefox -name firefox"
|
||||||
self.driver = webdriver.Firefox(
|
# ).split("\n")[-1]
|
||||||
options=firefox_options, service=firefox_services
|
# self.driver = webdriver.Firefox(
|
||||||
)
|
# options=firefox_options, service=firefox_services
|
||||||
|
# )
|
||||||
|
raise e
|
||||||
|
print("The driver is launched!")
|
||||||
|
|
||||||
# Ajout de l'enregistrement
|
# Ajout de l'enregistrement
|
||||||
if self.config.record_mode:
|
if self.config.record_mode:
|
||||||
|
|
@ -152,66 +327,100 @@ class SeleniumLib(object):
|
||||||
|
|
||||||
# Install DarkReader to help my eyes
|
# Install DarkReader to help my eyes
|
||||||
# TODO do a script to check if it's the last version
|
# TODO do a script to check if it's the last version
|
||||||
if not self.config.no_dark_mode:
|
if self.config.use_firefox_driver and not self.config.use_network:
|
||||||
self.driver.install_addon(
|
if not self.config.no_dark_mode:
|
||||||
"./script/selenium/darkreader-firefox.xpi", temporary=True
|
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]",
|
|
||||||
)
|
|
||||||
# Enable Run in Private Windows
|
|
||||||
try:
|
|
||||||
self.click(
|
|
||||||
"/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[6]/div/label[1]/input",
|
|
||||||
)
|
)
|
||||||
except Exception:
|
self.driver.install_addon(
|
||||||
# For old version before Firefox 138
|
"./script/selenium/odoo_debug-4.0.xpi", temporary=True
|
||||||
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
|
if (
|
||||||
# Back
|
not self.config.not_private_mode
|
||||||
self.click(
|
and not self.config.no_dark_mode
|
||||||
"/html/body/div/div[2]/addon-page-header/div/div[2]/button"
|
):
|
||||||
)
|
self.driver.get("about:addons")
|
||||||
self.click(
|
# Enable Dark Reader into incognito
|
||||||
"/html/body/div/div[2]/div/addon-list/section[1]/addon-card[2]/div/div/div/div/button",
|
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[2]/div/addon-options/panel-list/panel-item[5]",
|
|
||||||
)
|
|
||||||
# Enable Run in Private Windows
|
|
||||||
try:
|
|
||||||
self.click(
|
self.click(
|
||||||
"/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[6]/div/label[1]/input",
|
"/html/body/div/div[2]/div/addon-list/section[1]/addon-card/div/div/div/div/button",
|
||||||
)
|
)
|
||||||
except Exception:
|
|
||||||
# For old version before Firefox 138
|
|
||||||
self.click(
|
self.click(
|
||||||
"/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[5]/div/label[1]/input",
|
"/html/body/div/div[2]/div/addon-list/section[1]/addon-card/div/addon-options/panel-list/panel-item[5]",
|
||||||
)
|
)
|
||||||
|
# Enable Run in Private Windows
|
||||||
|
try:
|
||||||
|
self.click(
|
||||||
|
"/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[6]/div/label[1]/input",
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
# For old version before Firefox 138
|
||||||
|
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]",
|
||||||
|
)
|
||||||
|
# Enable Run in Private Windows
|
||||||
|
try:
|
||||||
|
self.click(
|
||||||
|
"/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[6]/div/label[1]/input",
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
# For old version before Firefox 138
|
||||||
|
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
|
# Ouvrez la page web
|
||||||
if not ignore_open_web:
|
if not ignore_open_web:
|
||||||
self.driver.get(f"{self.config.url}/web")
|
self.driver.get(f"{self.config.url}/web")
|
||||||
|
|
||||||
# Close tab opening by DarkReader
|
# Close tab opening by DarkReader
|
||||||
if self.config.not_private_mode and not self.config.no_dark_mode:
|
if self.config.use_firefox_driver and not self.config.use_network:
|
||||||
self.driver.switch_to.window(self.driver.window_handles[-1])
|
if self.config.not_private_mode and not self.config.no_dark_mode:
|
||||||
self.driver.close()
|
self.driver.switch_to.window(self.driver.window_handles[-1])
|
||||||
self.driver.switch_to.window(self.driver.window_handles[0])
|
self.driver.close()
|
||||||
|
self.driver.switch_to.window(self.driver.window_handles[0])
|
||||||
|
|
||||||
|
def get_kdbx(self):
|
||||||
|
if self.kdbx:
|
||||||
|
return self.kdbx
|
||||||
|
print("Open KDBX")
|
||||||
|
# Open file
|
||||||
|
chemin_fichier_kdbx = self.config_file.get_config(["kdbx", "path"])
|
||||||
|
if not chemin_fichier_kdbx:
|
||||||
|
root = tk.Tk()
|
||||||
|
root.withdraw() # Hide the main window
|
||||||
|
chemin_fichier_kdbx = filedialog.askopenfilename(
|
||||||
|
title="Select a File",
|
||||||
|
filetypes=(("KeepassX files", "*.kdbx"),),
|
||||||
|
)
|
||||||
|
if not chemin_fichier_kdbx:
|
||||||
|
# _logger.error(f"KDBX is not configured, please fill {CONFIG_FILE}")
|
||||||
|
return
|
||||||
|
|
||||||
|
mot_de_passe_kdbx = self.config_file.get_config(["kdbx", "password"])
|
||||||
|
if not mot_de_passe_kdbx:
|
||||||
|
mot_de_passe_kdbx = getpass.getpass(
|
||||||
|
prompt="Entrez votre mot de passe : "
|
||||||
|
)
|
||||||
|
|
||||||
|
kp = PyKeePass(chemin_fichier_kdbx, password=mot_de_passe_kdbx)
|
||||||
|
|
||||||
|
if kp:
|
||||||
|
self.kdbx = kp
|
||||||
|
return kp
|
||||||
|
|
||||||
def get_kdbx(self):
|
def get_kdbx(self):
|
||||||
if self.kdbx:
|
if self.kdbx:
|
||||||
|
|
@ -283,17 +492,46 @@ class SeleniumLib(object):
|
||||||
button.click()
|
button.click()
|
||||||
return button
|
return button
|
||||||
|
|
||||||
def get_element(self, by: str = By.ID, value: str = None, timeout=5):
|
def get_element(
|
||||||
|
self,
|
||||||
|
by: str = By.ID,
|
||||||
|
value: str = None,
|
||||||
|
timeout=5,
|
||||||
|
wait_clickable=False,
|
||||||
|
is_visible=True,
|
||||||
|
):
|
||||||
|
only_one = False
|
||||||
wait = WebDriverWait(self.driver, timeout)
|
wait = WebDriverWait(self.driver, timeout)
|
||||||
ele = wait.until(
|
if wait_clickable:
|
||||||
EC.visibility_of_any_elements_located(
|
ele = wait.until(
|
||||||
(
|
EC.element_to_be_clickable(
|
||||||
by,
|
(
|
||||||
value,
|
by,
|
||||||
|
value,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
elif is_visible:
|
||||||
|
ele = wait.until(
|
||||||
|
EC.visibility_of_any_elements_located(
|
||||||
|
(
|
||||||
|
by,
|
||||||
|
value,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
only_one = True
|
||||||
|
ele = wait.until(
|
||||||
|
EC.presence_of_element_located(
|
||||||
|
(
|
||||||
|
by,
|
||||||
|
value,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if only_one:
|
||||||
|
return ele
|
||||||
return ele[0]
|
return ele[0]
|
||||||
|
|
||||||
def get_element_not_visible(
|
def get_element_not_visible(
|
||||||
|
|
@ -431,13 +669,14 @@ class SeleniumLib(object):
|
||||||
viewport_ele_value: str = None,
|
viewport_ele_value: str = None,
|
||||||
element: WebElement = None,
|
element: WebElement = None,
|
||||||
with_index: bool = False,
|
with_index: bool = False,
|
||||||
|
is_visible=True,
|
||||||
index_of_list: int = 0,
|
index_of_list: int = 0,
|
||||||
):
|
):
|
||||||
# ele = self.driver.find_element(by, value)
|
# ele = self.driver.find_element(by, value)
|
||||||
if element:
|
if element:
|
||||||
ele = element
|
ele = element
|
||||||
else:
|
else:
|
||||||
ele = self.get_element(by, value, timeout)
|
ele = self.get_element(by, value, timeout, is_visible=is_visible)
|
||||||
if not no_scroll:
|
if not no_scroll:
|
||||||
viewport_ele = None
|
viewport_ele = None
|
||||||
if viewport_ele_value:
|
if viewport_ele_value:
|
||||||
|
|
@ -742,40 +981,40 @@ class SeleniumLib(object):
|
||||||
|
|
||||||
# Website
|
# Website
|
||||||
def odoo_show_robot_message(
|
def odoo_show_robot_message(
|
||||||
self, msg="Ho no!", hide_message_after_x_seconds=0
|
self, msg="Ho no!", hide_message_after_x_seconds=0, robot_base64=None
|
||||||
):
|
):
|
||||||
# Injecter l'animation SVG dans la page
|
# Injecter l'animation SVG dans la page
|
||||||
script_text = ""
|
script_text = ""
|
||||||
if msg:
|
if msg:
|
||||||
msg_to_print = msg.replace("'", "\\'")
|
msg_to_print = msg.replace("'", "\\'")
|
||||||
script_text = f"""
|
lst_mst_to_print = msg_to_print.split("\n")
|
||||||
// Ajouter le texte
|
script_text = ""
|
||||||
const textElement = document.createElement('div');
|
for index, line in enumerate(lst_mst_to_print):
|
||||||
textElement.innerText = '{msg_to_print}';
|
script_text += f"""
|
||||||
textElement.style.color = '#FFFFFF';
|
// Ajouter le texte
|
||||||
textElement.style.fontSize = '24px';
|
const textElement_{index} = document.createElement('div');
|
||||||
textElement.style.marginBottom = '20px';
|
textElement_{index}.textContent = '{line}';
|
||||||
textElement.style.fontWeight = 'bold';
|
textElement_{index}.style.color = '#FFFFFF';
|
||||||
|
textElement_{index}.style.fontSize = '24px';
|
||||||
|
textElement_{index}.style.marginBottom = '20px';
|
||||||
|
textElement_{index}.style.fontWeight = 'bold';
|
||||||
|
|
||||||
overlay.appendChild(textElement);
|
overlay.appendChild(textElement_{index});
|
||||||
"""
|
"""
|
||||||
script = (
|
if robot_base64:
|
||||||
"""
|
script_robot = ""
|
||||||
(function() {
|
script_add_robot = f"""
|
||||||
// Créer un div pour l'overlay
|
const img = new Image();
|
||||||
const overlay = document.createElement('div');
|
img.alt = 'Robot';
|
||||||
overlay.id = 'uniqueOverlay'; // Ajout de l'ID
|
img.className = 'cute-robot';
|
||||||
overlay.style.position = 'fixed';
|
img.style.width = '150px';
|
||||||
overlay.style.top = '0';
|
img.style.cursor = 'pointer';
|
||||||
overlay.style.left = '0';
|
|
||||||
overlay.style.width = '100%';
|
|
||||||
overlay.style.height = '100%';
|
|
||||||
overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
|
|
||||||
overlay.style.display = 'flex';
|
|
||||||
overlay.style.justifyContent = 'center';
|
|
||||||
overlay.style.alignItems = 'center';
|
|
||||||
overlay.style.zIndex = '9999';
|
|
||||||
|
|
||||||
|
img.src = '{robot_base64}';
|
||||||
|
overlay.appendChild(img);
|
||||||
|
"""
|
||||||
|
else:
|
||||||
|
script_robot = """
|
||||||
// Contenu SVG du robot
|
// Contenu SVG du robot
|
||||||
const svgContent = `
|
const svgContent = `
|
||||||
<svg class="cute-robot" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 150" style="width: 150px; cursor: pointer;">
|
<svg class="cute-robot" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 150" style="width: 150px; cursor: pointer;">
|
||||||
|
|
@ -801,11 +1040,32 @@ class SeleniumLib(object):
|
||||||
<rect x="50" y="120" width="15" height="30" rx="5" ry="5" fill="#388E3C"/>
|
<rect x="50" y="120" width="15" height="30" rx="5" ry="5" fill="#388E3C"/>
|
||||||
</svg>
|
</svg>
|
||||||
`;
|
`;
|
||||||
|
"""
|
||||||
|
script_add_robot = """
|
||||||
|
// Ajouter le contenu SVG au div
|
||||||
|
overlay.innerHTML += svgContent;
|
||||||
|
"""
|
||||||
|
script = (
|
||||||
|
"""
|
||||||
|
(function() {
|
||||||
|
// Créer un div pour l'overlay
|
||||||
|
const overlay = document.createElement('div');
|
||||||
|
overlay.id = 'uniqueOverlay'; // Ajout de l'ID
|
||||||
|
overlay.style.position = 'fixed';
|
||||||
|
overlay.style.top = '0';
|
||||||
|
overlay.style.left = '0';
|
||||||
|
overlay.style.width = '100%';
|
||||||
|
overlay.style.height = '100%';
|
||||||
|
overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
|
||||||
|
overlay.style.display = 'flex';
|
||||||
|
overlay.style.justifyContent = 'center';
|
||||||
|
overlay.style.alignItems = 'center';
|
||||||
|
overlay.style.zIndex = '9999';
|
||||||
"""
|
"""
|
||||||
|
+ script_robot
|
||||||
+ script_text
|
+ script_text
|
||||||
|
+ script_add_robot
|
||||||
+ """
|
+ """
|
||||||
// Ajouter le contenu SVG au div
|
|
||||||
overlay.innerHTML += svgContent;
|
|
||||||
|
|
||||||
// Ajouter un gestionnaire de clic pour supprimer l'overlay
|
// Ajouter un gestionnaire de clic pour supprimer l'overlay
|
||||||
overlay.onclick = function() {
|
overlay.onclick = function() {
|
||||||
|
|
@ -856,7 +1116,7 @@ class SeleniumLib(object):
|
||||||
|
|
||||||
def odoo_web_click_principal_menu(self):
|
def odoo_web_click_principal_menu(self):
|
||||||
# Click menu button
|
# Click menu button
|
||||||
if self.odoo_version == "16.0":
|
if self.odoo_version in ["16.0", "17.0", "18.0"]:
|
||||||
button = self.click_with_mouse_move(
|
button = self.click_with_mouse_move(
|
||||||
By.XPATH,
|
By.XPATH,
|
||||||
"//button[contains(@class, 'dropdown-toggle') and"
|
"//button[contains(@class, 'dropdown-toggle') and"
|
||||||
|
|
@ -869,6 +1129,119 @@ class SeleniumLib(object):
|
||||||
)
|
)
|
||||||
return button
|
return button
|
||||||
|
|
||||||
|
def odoo_web_click_item_list(self, index=0, field_name="name"):
|
||||||
|
# Click item list
|
||||||
|
all_row = self.get_all_element(
|
||||||
|
by=By.XPATH,
|
||||||
|
value=f"//tr[contains(@class, 'o_data_row')]/td[contains(@name, '{field_name}')]",
|
||||||
|
timeout=10,
|
||||||
|
)
|
||||||
|
row = all_row[index] if index < len(all_row) else all_row[-1]
|
||||||
|
button = self.click_with_mouse_move(element=row)
|
||||||
|
return button
|
||||||
|
|
||||||
|
def odoo_web_click_open_search(self):
|
||||||
|
# Click search button
|
||||||
|
button = self.click_with_mouse_move(
|
||||||
|
By.XPATH,
|
||||||
|
"//button[contains(@class, 'o_searchview_dropdown_toggler')]",
|
||||||
|
timeout=10,
|
||||||
|
)
|
||||||
|
return button
|
||||||
|
|
||||||
|
def odoo_web_click_open_search_add_group_custom(self, group_name):
|
||||||
|
# Add personalize group
|
||||||
|
button = self.click_with_mouse_move(
|
||||||
|
By.XPATH,
|
||||||
|
value="//select[contains(@class, 'o_add_custom_group_menu')]",
|
||||||
|
timeout=10,
|
||||||
|
)
|
||||||
|
if self.wait_human_time:
|
||||||
|
time.sleep(1)
|
||||||
|
select_elem = self.get_element(
|
||||||
|
By.XPATH,
|
||||||
|
value="//select[contains(@class, 'o_add_custom_group_menu')]",
|
||||||
|
timeout=10,
|
||||||
|
wait_clickable=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
select_obj = Select(select_elem)
|
||||||
|
# (ex: <option value="customer">Client</option>)
|
||||||
|
select_obj.select_by_value(group_name)
|
||||||
|
return select_elem
|
||||||
|
|
||||||
|
def odoo_web_click_open_search_filter(
|
||||||
|
self,
|
||||||
|
filter_label=None,
|
||||||
|
filter_sub_label=None,
|
||||||
|
lst_update_condition=None,
|
||||||
|
):
|
||||||
|
if not lst_update_condition:
|
||||||
|
lst_update_condition = []
|
||||||
|
if filter_label:
|
||||||
|
button = self.click_with_mouse_move(
|
||||||
|
By.XPATH,
|
||||||
|
value=f"//button[contains(@class,'o_menu_item') and contains(normalize-space(.), '{filter_label}')]",
|
||||||
|
timeout=10,
|
||||||
|
)
|
||||||
|
if filter_sub_label:
|
||||||
|
button = self.click_with_mouse_move(
|
||||||
|
By.XPATH,
|
||||||
|
value=f"//span[contains(@class,'o_item_option') and contains(normalize-space(.), '{filter_sub_label}')]",
|
||||||
|
timeout=10,
|
||||||
|
)
|
||||||
|
if lst_update_condition:
|
||||||
|
filter_text = f"{filter_label}: {filter_sub_label}"
|
||||||
|
button = self.click_with_mouse_move(
|
||||||
|
By.XPATH,
|
||||||
|
value=f"//small[contains(@class,'o_facet_value') and contains(normalize-space(.), '{filter_text}')]/../..//i[contains(@class,'fa-cog')]",
|
||||||
|
timeout=10,
|
||||||
|
is_visible=False,
|
||||||
|
)
|
||||||
|
time.sleep(1)
|
||||||
|
for item_update_condition in lst_update_condition:
|
||||||
|
condition_value = item_update_condition.get("condition")
|
||||||
|
if condition_value:
|
||||||
|
select_elem = self.click_with_mouse_move(
|
||||||
|
By.XPATH,
|
||||||
|
value=f"//div[contains(@class,'modal-content')]//select[contains(@class,'pe-3')]",
|
||||||
|
timeout=10,
|
||||||
|
is_visible=False,
|
||||||
|
)
|
||||||
|
select_obj = Select(select_elem)
|
||||||
|
# (ex: <option value="customer">Client</option>)
|
||||||
|
select_obj.select_by_value(condition_value)
|
||||||
|
else:
|
||||||
|
_logger.error(
|
||||||
|
f"Not supported item_update_condition '{item_update_condition}'"
|
||||||
|
)
|
||||||
|
# Save
|
||||||
|
button = self.click_with_mouse_move(
|
||||||
|
By.XPATH,
|
||||||
|
value=f"//footer[contains(@class,'modal-footer')]//button[contains(@class,'btn-primary') and contains(normalize-space(.), 'Confirmer')]",
|
||||||
|
timeout=10,
|
||||||
|
)
|
||||||
|
|
||||||
|
def odoo_fill_search_input(self, text, selection_research=None):
|
||||||
|
input_elem = self.click_with_mouse_move(
|
||||||
|
By.XPATH,
|
||||||
|
value="//input[contains(@class, 'o_searchview_input')]",
|
||||||
|
timeout=10,
|
||||||
|
)
|
||||||
|
input_elem.send_keys(text)
|
||||||
|
time.sleep(1)
|
||||||
|
if not selection_research:
|
||||||
|
input_elem.send_keys(Keys.ENTER)
|
||||||
|
else:
|
||||||
|
input_autocomplete_elem = self.click_with_mouse_move(
|
||||||
|
By.XPATH,
|
||||||
|
value="//ul[contains(@class,'o_searchview_autocomplete')]"
|
||||||
|
f"//li[contains(@class,'o_menu_item') and .//b[normalize-space(.)='{selection_research}']]"
|
||||||
|
"//a[not(contains(@class,'o_expand'))]",
|
||||||
|
)
|
||||||
|
|
||||||
|
return input_elem
|
||||||
|
|
||||||
def odoo_web_principal_menu_click_root_menu(self, from_text=""):
|
def odoo_web_principal_menu_click_root_menu(self, from_text=""):
|
||||||
if not from_text:
|
if not from_text:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
|
|
@ -952,6 +1325,23 @@ class SeleniumLib(object):
|
||||||
"o_form_button_save"
|
"o_form_button_save"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def odoo_web_change_view(
|
||||||
|
self, view_name="list", raise_error=False, timeout=5
|
||||||
|
):
|
||||||
|
if view_name not in ["list", "kanban", "timeline"]:
|
||||||
|
msg = f"odoo_web_change_view view_name '{view_name}' invalid"
|
||||||
|
if raise_error:
|
||||||
|
raise Exception(msg)
|
||||||
|
_logger.error(msg)
|
||||||
|
return None
|
||||||
|
|
||||||
|
status_button = self.click_with_mouse_move(
|
||||||
|
by=By.XPATH,
|
||||||
|
value=f"//nav[contains(@class, 'o_cp_switch_buttons')]/button[contains(@class, 'o_{view_name}')]",
|
||||||
|
)
|
||||||
|
print(f"Change view '{view_name}' cliqué.")
|
||||||
|
return status_button
|
||||||
|
|
||||||
def odoo_web_form_click_web_publish_action(self):
|
def odoo_web_form_click_web_publish_action(self):
|
||||||
return self.odoo_web_form_click_button_action("website_publish_button")
|
return self.odoo_web_form_click_button_action("website_publish_button")
|
||||||
|
|
||||||
|
|
@ -1059,14 +1449,20 @@ class SeleniumLib(object):
|
||||||
checkbox_div.click()
|
checkbox_div.click()
|
||||||
# TODO improve speed by observation of comportement
|
# TODO improve speed by observation of comportement
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
checkbox_date_div = self.driver.find_element(
|
|
||||||
By.CSS_SELECTOR, ".bootstrap-datetimepicker-widget"
|
|
||||||
)
|
|
||||||
# time.sleep(0.5)
|
|
||||||
str_date_today = date_to_select.strftime("%Y-%m-%d")
|
str_date_today = date_to_select.strftime("%Y-%m-%d")
|
||||||
new_value = checkbox_date_div.find_element(
|
if self.odoo_version in ["17.0", "18.0"]:
|
||||||
By.XPATH, f"//td[@data-day='{str_date_today}']"
|
checkbox_date_div = self.driver.find_element(
|
||||||
)
|
By.CSS_SELECTOR, ".o_datetime_picker"
|
||||||
|
)
|
||||||
|
new_value = self.select_date(self.driver, date_to_select)
|
||||||
|
else:
|
||||||
|
checkbox_date_div = self.driver.find_element(
|
||||||
|
By.CSS_SELECTOR, ".bootstrap-datetimepicker-widget"
|
||||||
|
)
|
||||||
|
# time.sleep(0.5)
|
||||||
|
new_value = checkbox_date_div.find_element(
|
||||||
|
By.XPATH, f"//td[@data-day='{str_date_today}']"
|
||||||
|
)
|
||||||
new_value.click()
|
new_value.click()
|
||||||
return new_value
|
return new_value
|
||||||
|
|
||||||
|
|
@ -1108,6 +1504,9 @@ class SeleniumLib(object):
|
||||||
time.sleep(var_wait_time)
|
time.sleep(var_wait_time)
|
||||||
self.video_recorder.start()
|
self.video_recorder.start()
|
||||||
|
|
||||||
|
def quit(self):
|
||||||
|
self.driver.quit()
|
||||||
|
|
||||||
def stop_record(self):
|
def stop_record(self):
|
||||||
time.sleep(self.config.selenium_default_delay_presentation)
|
time.sleep(self.config.selenium_default_delay_presentation)
|
||||||
|
|
||||||
|
|
@ -1122,10 +1521,13 @@ class SeleniumLib(object):
|
||||||
".webm", ".mp4"
|
".webm", ".mp4"
|
||||||
)
|
)
|
||||||
if self.config.selenium_video_auto_convert_mp4:
|
if self.config.selenium_video_auto_convert_mp4:
|
||||||
os.popen(
|
with_auto_fix = True
|
||||||
"ffmpeg -i"
|
if with_auto_fix:
|
||||||
f" {self.filename_recording} {filename_recording_mp4}"
|
cmd = f'ffmpeg -i {self.filename_recording} -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" -c:v libx264 -pix_fmt yuv420p -crf 23 -preset veryfast -c:a aac -b:a 160k -movflags +faststart {filename_recording_mp4}'
|
||||||
)
|
else:
|
||||||
|
cmd = f"ffmpeg -i {self.filename_recording} {filename_recording_mp4}"
|
||||||
|
print(cmd)
|
||||||
|
os.popen(cmd)
|
||||||
|
|
||||||
if self.config.selenium_video_auto_play_video:
|
if self.config.selenium_video_auto_play_video:
|
||||||
print(f"Play video {self.filename_recording}")
|
print(f"Play video {self.filename_recording}")
|
||||||
|
|
@ -1193,6 +1595,94 @@ class SeleniumLib(object):
|
||||||
|
|
||||||
return date_naissance.strftime("%Y-%m-%d")
|
return date_naissance.strftime("%Y-%m-%d")
|
||||||
|
|
||||||
|
def _get_visible_month_year(self, picker):
|
||||||
|
header = picker.find_element(
|
||||||
|
By.CSS_SELECTOR, ".o_datetime_picker_header .o_header_part"
|
||||||
|
)
|
||||||
|
text = header.text.strip().lower() # ex: "octobre 2025"
|
||||||
|
parts = text.split()
|
||||||
|
# s'il y a des espaces insécables ou formats bizarres
|
||||||
|
mois_txt = parts[0].replace("\xa0", " ")
|
||||||
|
annee = int(parts[-1])
|
||||||
|
mois = MONTHS_FR[mois_txt]
|
||||||
|
return (
|
||||||
|
mois,
|
||||||
|
annee,
|
||||||
|
header.text,
|
||||||
|
) # on retourne aussi le texte exact pour attendre le changement
|
||||||
|
|
||||||
|
def select_date(self, driver, date_to_select):
|
||||||
|
# 1) ouvrir/viser le datepicker (si besoin, clique l'input avant)
|
||||||
|
picker = WebDriverWait(driver, 10).until(
|
||||||
|
EC.visibility_of_element_located(
|
||||||
|
(By.CSS_SELECTOR, ".o_datetime_picker")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 2) naviguer au bon mois
|
||||||
|
max_hops = 24 # sécurité (2 ans)
|
||||||
|
for _ in range(max_hops):
|
||||||
|
mois_vis, annee_vis, header_txt = self._get_visible_month_year(
|
||||||
|
picker
|
||||||
|
)
|
||||||
|
if (annee_vis, mois_vis) == (
|
||||||
|
date_to_select.year,
|
||||||
|
date_to_select.month,
|
||||||
|
):
|
||||||
|
break
|
||||||
|
|
||||||
|
# bouton suivant/précédent dans l'entête du picker courant
|
||||||
|
if (annee_vis, mois_vis) < (
|
||||||
|
date_to_select.year,
|
||||||
|
date_to_select.month,
|
||||||
|
):
|
||||||
|
btn = picker.find_element(
|
||||||
|
By.CSS_SELECTOR, ".o_datetime_picker_header .o_next"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
btn = picker.find_element(
|
||||||
|
By.CSS_SELECTOR, ".o_datetime_picker_header .o_previous"
|
||||||
|
)
|
||||||
|
|
||||||
|
btn.click()
|
||||||
|
# attendre que l'en-tête change pour éviter les doubles clics trop rapides
|
||||||
|
WebDriverWait(driver, 10).until(
|
||||||
|
EC.text_to_be_present_in_element(
|
||||||
|
(
|
||||||
|
By.CSS_SELECTOR,
|
||||||
|
".o_datetime_picker_header .o_header_part",
|
||||||
|
),
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
WebDriverWait(driver, 10).until(
|
||||||
|
lambda d: picker.find_element(
|
||||||
|
By.CSS_SELECTOR, ".o_datetime_picker_header .o_header_part"
|
||||||
|
).text
|
||||||
|
!= header_txt
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise RuntimeError(
|
||||||
|
"Impossible d'atteindre le mois voulu dans le délai imparti."
|
||||||
|
)
|
||||||
|
|
||||||
|
# 3) cliquer le jour (les jours cliquables sont des <button> avec un <span> = numéro)
|
||||||
|
day = str(int(date_to_select.day)) # sans zéro en tête
|
||||||
|
day_xpath = f".//button[contains(@class,'o_date_item_cell') and .//span[normalize-space(text())='{day}']]"
|
||||||
|
|
||||||
|
day_btn = WebDriverWait(picker, 10).until(
|
||||||
|
EC.element_to_be_clickable((By.XPATH, day_xpath))
|
||||||
|
)
|
||||||
|
|
||||||
|
return day_btn
|
||||||
|
|
||||||
|
|
||||||
|
def get_args(parser):
|
||||||
|
args = parser.parse_args()
|
||||||
|
if args.use_chrome_driver:
|
||||||
|
args.use_firefox_driver = False
|
||||||
|
return args
|
||||||
|
|
||||||
|
|
||||||
def fill_parser(parser):
|
def fill_parser(parser):
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
|
@ -1209,12 +1699,37 @@ def fill_parser(parser):
|
||||||
help="Pause at the end of an action.",
|
help="Pause at the end of an action.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
group_animation.add_argument(
|
||||||
|
"--human_time_speed",
|
||||||
|
action="store_true",
|
||||||
|
help="Will wait after each action to help human to follow",
|
||||||
|
)
|
||||||
|
|
||||||
group_browser = parser.add_argument_group(title="Browser")
|
group_browser = parser.add_argument_group(title="Browser")
|
||||||
group_browser.add_argument(
|
group_browser.add_argument(
|
||||||
"--not_private_mode",
|
"--not_private_mode",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="Default is private mode.",
|
help="Default is private mode.",
|
||||||
)
|
)
|
||||||
|
group_browser.add_argument(
|
||||||
|
"--use_chrome_driver",
|
||||||
|
action="store_true",
|
||||||
|
help="Switch to chrome instead of great Firefox.",
|
||||||
|
)
|
||||||
|
group_browser.add_argument(
|
||||||
|
"--use_firefox_driver",
|
||||||
|
action="store_true",
|
||||||
|
default=True,
|
||||||
|
help="The default is firefox.",
|
||||||
|
)
|
||||||
|
group_browser.add_argument(
|
||||||
|
"--use_network",
|
||||||
|
help="Specify the adress, example: http://localhost:4444",
|
||||||
|
)
|
||||||
|
group_browser.add_argument(
|
||||||
|
"--window_size",
|
||||||
|
help="Example 1920,1080",
|
||||||
|
)
|
||||||
group_browser.add_argument(
|
group_browser.add_argument(
|
||||||
"--headless",
|
"--headless",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,15 @@
|
||||||
|
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
import gi
|
try:
|
||||||
|
import gi
|
||||||
|
|
||||||
|
gi.require_version("Gst", "1.0")
|
||||||
|
from gi.repository import Gst
|
||||||
|
except ImportError:
|
||||||
|
print("Please read installation script/selenium/install.md")
|
||||||
|
raise
|
||||||
|
|
||||||
gi.require_version("Gst", "1.0")
|
|
||||||
from gi.repository import Gst
|
|
||||||
|
|
||||||
Gst.init(None)
|
Gst.init(None)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,15 @@ import os
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import selenium_lib
|
new_path = os.path.normpath(
|
||||||
|
os.path.join(os.path.dirname(__file__), "..", "..")
|
||||||
|
)
|
||||||
|
sys.path.append(new_path)
|
||||||
|
|
||||||
from selenium.webdriver.common.by import By
|
from selenium.webdriver.common.by import By
|
||||||
|
|
||||||
|
from script.selenium import selenium_lib
|
||||||
|
|
||||||
|
|
||||||
def fill_parser(parser):
|
def fill_parser(parser):
|
||||||
group_login = parser.add_argument_group(title="Login")
|
group_login = parser.add_argument_group(title="Login")
|
||||||
|
|
@ -30,13 +36,24 @@ def fill_parser(parser):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def run(config, selenium_tool):
|
def run(
|
||||||
|
config,
|
||||||
|
selenium_tool,
|
||||||
|
default_email_auth=None,
|
||||||
|
default_password_auth=None,
|
||||||
|
no_try_test=False,
|
||||||
|
):
|
||||||
# Trouvez les éléments du formulaire
|
# Trouvez les éléments du formulaire
|
||||||
courriel_input = selenium_tool.get_element(by=By.NAME, value="login")
|
courriel_input = selenium_tool.get_element(by=By.NAME, value="login")
|
||||||
mot_de_passe_input = selenium_tool.get_element(by=By.NAME, value="password")
|
mot_de_passe_input = selenium_tool.get_element(
|
||||||
|
by=By.NAME, value="password"
|
||||||
|
)
|
||||||
# div_connexion_button = selenium_tool.get_element(by=By.CLASS_NAME, value="oe_login_buttons")
|
# div_connexion_button = selenium_tool.get_element(by=By.CLASS_NAME, value="oe_login_buttons")
|
||||||
connexion_button = selenium_tool.get_element(by=By.CSS_SELECTOR, value="[type='submit']")
|
connexion_button = selenium_tool.get_element(
|
||||||
|
by=By.CSS_SELECTOR, value="[type='submit']"
|
||||||
|
)
|
||||||
|
|
||||||
|
actual_url = selenium_tool.driver.current_url
|
||||||
# try:
|
# try:
|
||||||
# connexion_button = selenium_tool.driver.find_element(
|
# connexion_button = selenium_tool.driver.find_element(
|
||||||
# By.XPATH,
|
# By.XPATH,
|
||||||
|
|
@ -51,8 +68,18 @@ def run(config, selenium_tool):
|
||||||
# )
|
# )
|
||||||
|
|
||||||
# Remplissez le courriel et le mot de passe
|
# Remplissez le courriel et le mot de passe
|
||||||
courriel_input.send_keys(config.default_email_auth)
|
email_auth = (
|
||||||
mot_de_passe_input.send_keys(config.default_password_auth)
|
default_email_auth if default_email_auth else config.default_email_auth
|
||||||
|
)
|
||||||
|
pass_auth = (
|
||||||
|
default_password_auth
|
||||||
|
if default_password_auth
|
||||||
|
else config.default_password_auth
|
||||||
|
)
|
||||||
|
courriel_input.clear()
|
||||||
|
mot_de_passe_input.clear()
|
||||||
|
courriel_input.send_keys(email_auth)
|
||||||
|
mot_de_passe_input.send_keys(pass_auth)
|
||||||
|
|
||||||
# Cliquez sur le bouton "Connexion"
|
# Cliquez sur le bouton "Connexion"
|
||||||
try:
|
try:
|
||||||
|
|
@ -100,6 +127,21 @@ def run(config, selenium_tool):
|
||||||
# )
|
# )
|
||||||
# )
|
# )
|
||||||
|
|
||||||
|
if not no_try_test:
|
||||||
|
time.sleep(1)
|
||||||
|
if actual_url in [
|
||||||
|
selenium_tool.driver.current_url,
|
||||||
|
f"{selenium_tool.driver.current_url}?redirect=%2Fweb%3F",
|
||||||
|
]:
|
||||||
|
run(
|
||||||
|
config,
|
||||||
|
selenium_tool,
|
||||||
|
default_email_auth="test",
|
||||||
|
default_password_auth="test",
|
||||||
|
no_try_test=True,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
# Remove chatbot if open, because will crash wizard div[4] (to div[5])
|
# Remove chatbot if open, because will crash wizard div[4] (to div[5])
|
||||||
selenium_tool.check_bot_chat_and_close()
|
selenium_tool.check_bot_chat_and_close()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue