Files
pxil-selenium-automation/tests/regression/exchange/idas/bidding/block_bulk_upload_actions.py
T

401 lines
12 KiB
Python

import json
from pathlib import Path
import time
from datetime import datetime
from selenium.common.exceptions import NoAlertPresentException, TimeoutException
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from tests.regression.ui_helpers import select_select2_value_by_container_id
def prepare_block_bulk_upload_page(driver, config, entry, upload_method):
product = config["product"]
bidding_config = config["exchange_bidding"]
block_config = bidding_config.get("block_bid", {})
_click_tab(driver, upload_method)
_click_block_bid_tab(driver)
_select_product_type(driver, product["product_type"])
_select_first_available_select2_value(
driver,
block_config.get("product_container_id", "s2id_ddlproduct3"),
[
block_config.get("product_code"),
product["product_code"],
],
)
_select_first_available_select2_value(
driver,
block_config.get("segment_container_id", "s2id_ddlSegment3"),
[product["trading_market"]],
)
if config["selected_role"] != "trading_member":
_select_first_available_select2_value(
driver,
block_config.get("tm_container_id", "s2id_ddlTMID3"),
[entry["tm_id"]],
)
def upload_block_bulk_file(
driver,
file_path,
success_timeout_seconds=1800,
poll_seconds=2,
progress_log_interval_seconds=60,
progress_log_label="block_file_upload",
):
upload_path = Path(file_path)
if not upload_path.exists() or not upload_path.is_file():
raise FileNotFoundError(f"Block bid upload file not found: {upload_path}")
file_input = _find_block_upload_input(driver)
_prepare_file_input(driver, file_input)
selected_at = datetime.now()
selected_monotonic = time.monotonic()
file_input.send_keys(str(upload_path.resolve()))
_accept_browser_upload_confirmation_if_present(driver)
success = wait_for_block_upload_success(
driver,
timeout_seconds=success_timeout_seconds,
poll_seconds=poll_seconds,
progress_log_interval_seconds=progress_log_interval_seconds,
progress_log_label=progress_log_label,
)
return _build_upload_timing(selected_at, selected_monotonic, success, [upload_path])
def upload_block_bulk_folder(
driver,
folder_path,
success_timeout_seconds=1800,
poll_seconds=2,
progress_log_interval_seconds=60,
progress_log_label="block_folder_upload",
):
upload_path = Path(folder_path)
if not upload_path.exists() or not upload_path.is_dir():
raise FileNotFoundError(f"Block bid upload folder not found: {upload_path}")
upload_files = [path for path in upload_path.rglob("*") if path.is_file()]
file_input = _find_block_upload_input(driver)
_prepare_file_input(driver, file_input)
selected_at = datetime.now()
selected_monotonic = time.monotonic()
file_input.send_keys(str(upload_path.resolve()))
_accept_browser_upload_confirmation_if_present(driver)
success = wait_for_block_upload_success(
driver,
timeout_seconds=success_timeout_seconds,
poll_seconds=poll_seconds,
progress_log_interval_seconds=progress_log_interval_seconds,
progress_log_label=progress_log_label,
)
return _build_upload_timing(selected_at, selected_monotonic, success, upload_files)
def wait_for_block_upload_success(
driver,
timeout_seconds=1800,
poll_seconds=2,
progress_log_interval_seconds=60,
progress_log_label="block_upload",
):
end_time = time.monotonic() + timeout_seconds
next_progress_log = time.monotonic() + progress_log_interval_seconds
last_message = ""
while time.monotonic() < end_time:
message = _current_upload_message(driver)
if message:
last_message = message
if _is_success_message(message):
return {
"message": message,
"displayed_at": datetime.now().isoformat(timespec="seconds"),
}
if progress_log_interval_seconds and time.monotonic() >= next_progress_log:
print(
f"Block upload progress [{progress_log_label}]: "
f"waiting for success message. Last message: {last_message or 'none'}"
)
next_progress_log = time.monotonic() + progress_log_interval_seconds
time.sleep(poll_seconds)
raise TimeoutException(
"Block upload success message did not appear within the timeout. "
f"Last visible message: {last_message or 'No status message found'}"
)
def save_block_bulk_upload_log(test_context, market, entry, upload_method, timing):
folder = Path(test_context.get("log_folder", test_context["folder"]))
folder.mkdir(parents=True, exist_ok=True)
side_name = entry.get("side", "")
log_name_parts = ["block_bulk_upload", upload_method, market]
if side_name:
log_name_parts.append(side_name)
log_name_parts.append(entry["tm_id"])
path = folder / f"{'_'.join(log_name_parts)}.json"
payload = {
"market": market,
"side": side_name,
"tm_id": entry["tm_id"],
"folder_name": entry.get("folder_name", ""),
"folder_path": entry.get("folder_path", ""),
"file_name": entry.get("file_name", ""),
"file_path": entry.get("upload_path", ""),
"upload_method": upload_method,
"timing": timing,
}
path.write_text(json.dumps(payload, indent=2), encoding="utf-8")
return str(path)
def _click_tab(driver, upload_method):
tab_href = "#Folder" if upload_method == "folder_upload" else "#File"
_click_by_xpath(
driver,
f"//a[@href='{tab_href}' or normalize-space()='{tab_href.lstrip('#')}']"
)
def _click_block_bid_tab(driver):
if _block_bid_fields_are_visible(driver):
return
_click_visible_by_xpath(
driver,
"//a[contains(normalize-space(),'Block Bid')]"
"|//span[contains(normalize-space(),'Block Bid')]/ancestor::a[1]"
"|//*[self::button][contains(normalize-space(),'Block Bid')]"
)
WebDriverWait(driver, 20).until(lambda _driver: _block_bid_fields_are_visible(_driver))
def _select_product_type(driver, product_type):
wait = WebDriverWait(driver, 20)
candidates = driver.find_elements(
By.XPATH,
"//select[contains(@id,'ProductType') or contains(@name,'ProductType')]"
"|//select[option[normalize-space()='IDAS']]"
)
for candidate in candidates:
if not candidate.is_displayed():
continue
try:
from selenium.webdriver.support.select import Select
Select(candidate).select_by_visible_text(product_type)
return
except Exception:
continue
wait.until(lambda _driver: candidates or True)
def _select_first_available_select2_value(driver, container_id, values):
last_error = None
for value in values:
if not value:
continue
try:
select_select2_value_by_container_id(
driver,
container_id,
value,
exact=True
)
return value
except TimeoutException as exc:
last_error = exc
if last_error:
raise last_error
raise ValueError(f"No values configured for select2 container '{container_id}'.")
def _find_block_upload_input(driver):
wait = WebDriverWait(driver, 30)
return wait.until(
lambda _driver: _first_displayed_or_existing(
_driver.find_elements(
By.XPATH,
"//input[@type='file' and ("
"@id='filepicker3' or contains(@id,'filepicker') or "
"contains(@id,'file') or contains(@name,'file') or @webkitdirectory"
")]"
)
) or False,
"No block bid upload input was found."
)
def _first_displayed_or_existing(elements):
for element in elements:
if element.is_displayed() and element.is_enabled():
return element
if elements:
return elements[0]
return None
def _prepare_file_input(driver, file_input):
driver.execute_script(
"""
arguments[0].style.display = 'block';
arguments[0].style.visibility = 'visible';
arguments[0].style.opacity = 1;
arguments[0].style.height = '20px';
arguments[0].style.width = '120px';
arguments[0].removeAttribute('disabled');
arguments[0].value = '';
""",
file_input
)
def _click_by_xpath(driver, xpath):
wait = WebDriverWait(driver, 20)
element = wait.until(EC.element_to_be_clickable((By.XPATH, xpath)))
driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", element)
try:
element.click()
except Exception:
driver.execute_script("arguments[0].click();", element)
def _click_visible_by_xpath(driver, xpath):
wait = WebDriverWait(driver, 20)
element = wait.until(lambda _driver: _first_clickable(_driver, xpath) or False)
driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", element)
try:
element.click()
except Exception:
driver.execute_script("arguments[0].click();", element)
def _first_clickable(driver, xpath):
for element in driver.find_elements(By.XPATH, xpath):
try:
if element.is_displayed() and element.is_enabled():
return element
except Exception:
continue
return None
def _block_bid_fields_are_visible(driver):
product_fields = driver.find_elements(By.ID, "s2id_ddlproduct3")
segment_fields = driver.find_elements(By.ID, "s2id_ddlSegment3")
upload_inputs = driver.find_elements(By.ID, "filepicker3")
return any(_is_visible(element) for element in product_fields) and (
any(_is_visible(element) for element in segment_fields)
or any(_is_visible(element) for element in upload_inputs)
)
def _is_visible(element):
try:
return element.is_displayed()
except Exception:
return False
def _accept_browser_upload_confirmation_if_present(driver):
try:
alert = driver.switch_to.alert
alert.accept()
return
except NoAlertPresentException:
pass
try:
ActionChains(driver).send_keys("\ue007").perform()
except Exception:
pass
def _current_upload_message(driver):
candidates = []
for locator in (
(By.ID, "successMsg"),
(By.ID, "divSuccess"),
(By.ID, "divInfo"),
(By.ID, "divError"),
):
candidates.extend(driver.find_elements(*locator))
candidates.extend(
driver.find_elements(
By.XPATH,
"//*[contains(@class,'alert') and not(contains(@style,'display: none'))]"
)
)
for candidate in candidates:
try:
if candidate.is_displayed():
text = candidate.text.strip()
if text:
return text
except Exception:
continue
return ""
def _is_success_message(message):
normalized_message = " ".join(str(message or "").split()).lower()
return (
"folder_uploaded_successfully" in normalized_message
or "folder uploaded successfully" in normalized_message
or "file_uploaded_successfully" in normalized_message
or "file uploaded successfully" in normalized_message
)
def _build_upload_timing(selected_at, selected_monotonic, success, upload_files):
success_monotonic = time.monotonic()
return {
"files_selected_at": selected_at.isoformat(timespec="seconds"),
"success_displayed_at": success["displayed_at"],
"duration_seconds": round(success_monotonic - selected_monotonic, 3),
"success_message": success["message"],
"file_count": len(upload_files),
"files": [str(path) for path in upload_files],
}