Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 32 additions & 6 deletions bank_integration/bank_integration/api/bank_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,14 @@ def __init__(

if getattr(self, "init"):
self.init()

if resume:
self.resume_session()
else:
self.login()

try:
if resume:
self.resume_session()
else:
self.login()
except Exception as e:
self.throw("Closing browser session. Unexpected error occurred: {}".format(str(e)))

def login(self):
pass

Expand Down Expand Up @@ -306,6 +308,30 @@ def cleanup_download_dir(self, delete_dir=False):
)


class ElementVisibleByJS:
"""
Custom EC that checks actual rendered size via getBoundingClientRect()
instead of Selenium's is_displayed(), which can fail for Angular components
that use CSS opacity/transforms to show/hide elements that stay in the DOM.
Has a .locator attribute so AnyEC._found_element tracking works correctly.
"""

def __init__(self, by, value):
self.locator = (by, value)

def __call__(self, driver):
els = driver.find_elements(*self.locator)
if not els:
return False
visible = [
e
for e in els
if driver.execute_script(
"var r=arguments[0].getBoundingClientRect(); return r.width>0 && r.height>0;",
e,
)
]
return visible[0] if visible else False
class AnyEC:
"""Use with WebDriverWait to combine expected_conditions
in an OR.
Expand Down
13 changes: 10 additions & 3 deletions bank_integration/bank_integration/api/hdfc_bank_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
from frappe.utils import getdate, today, add_months, add_days, flt
from frappe.utils.file_manager import save_file

from bank_integration.bank_integration.api.bank_api import BankAPI, AnyEC
from bank_integration.bank_integration.api.bank_api import (
BankAPI,
AnyEC,
ElementVisibleByJS,
)

# Selenium imports
from selenium.webdriver.support import expected_conditions as EC
Expand Down Expand Up @@ -75,7 +79,7 @@ def _handle_post_login_state(self):
)
),
EC.visibility_of_element_located((By.ID, "proceedBtn")),
EC.visibility_of_element_located((By.ID, "mfa-get-otp-btn")),
ElementVisibleByJS(By.ID, "mfa-get-otp-btn"),
EC.presence_of_element_located((By.TAG_NAME, "bb-retail-layout")),
EC.visibility_of_element_located((By.NAME, "fldOldPass")),
EC.visibility_of_element_located((By.NAME, "fldAnswer")),
Expand Down Expand Up @@ -144,9 +148,12 @@ def _handle_post_login_state(self):
self.handle_login_error()
return

self.handle_login_error()

def process_otp(self):
# here it again checks for the otp button in AnyEC because process_otp is used in two flows
# - login flow
# - payment flow
# both have different GET OTP button elements present
try:
self.wait_until(
AnyEC(
Expand Down