Skip to content

Commit be6966a

Browse files
author
dmy.berezovskyi
committed
fix
1 parent 6bff442 commit be6966a

File tree

4 files changed

+84
-20
lines changed

4 files changed

+84
-20
lines changed

core/driver.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from utils.error_handler import ErrorHandler, ErrorType
1111
from utils.logger import Logger, LogLevel
1212
from properties import Properties
13-
from utils.yaml_reader import YamlReader
13+
from utils.yaml_reader import YAMLReader
1414

1515
log = Logger(log_lvl=LogLevel.INFO).get_instance()
1616

@@ -42,7 +42,8 @@ def create_driver(self, environment, dr_type):
4242
pass
4343

4444
def get_desired_caps(self, browser="chrome"):
45-
caps = YamlReader.read_caps(browser)
45+
caps = YAMLReader.read_caps(browser)
46+
log.info(f"capabilities for driver {caps}")
4647
return caps
4748

4849

@@ -51,7 +52,7 @@ def create_driver(self, environment=None, dr_type=None):
5152
"""Tries to use ChromeDriverManager to install the latest driver,
5253
and if it fails, it falls back to a locally stored driver in resources."""
5354
try:
54-
log.info(f"Run local chrome driver")
55+
log.info(f"Run local chrome driver with {_init_driver_options()}")
5556
driver_path = ChromeDriverManager().install()
5657
driver = webdriver.Chrome(
5758
service=ChromeService(executable_path=driver_path),

src/pageobjects/base_page.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
TimeoutException, ElementNotVisibleException
99
)
1010

11+
from utils.logger import log
12+
1113
# Type alias for locators
1214
Locator = Tuple[By, str]
1315

@@ -101,6 +103,7 @@ def get_text(
101103
waiter = self._get_waiter(wait_type)
102104
return self.wait_for(locator, condition="present", waiter=waiter).text
103105

106+
@log()
104107
def get_title(self) -> str:
105108
"""
106109
Get the page title.

utils/helpers.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import time
2+
from functools import wraps
3+
4+
5+
def retry(retries=3, delay=2):
6+
def decorator(func):
7+
@wraps(func)
8+
def wrapper(*args, **kwargs):
9+
attempts = 0
10+
while attempts < retries:
11+
try:
12+
return func(*args, **kwargs)
13+
except Exception as e:
14+
attempts += 1
15+
print(f"Attempt {attempts} failed: {e}")
16+
time.sleep(delay)
17+
return func(*args, **kwargs)
18+
19+
return wrapper
20+
21+
return decorator

utils/logger.py

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import os
33
import time
44
from enum import Enum
5+
from typing import Optional, Callable, Any, Literal
56

67

78
class LogLevel(Enum):
@@ -14,41 +15,79 @@ class LogLevel(Enum):
1415
class Singleton(type):
1516
_instances = {}
1617

17-
def __call__(cls, *args, **kwargs):
18+
def __call__(cls, *args, **kwargs) -> Any:
1819
if cls not in cls._instances:
19-
cls._instances[cls] = super(Singleton, cls).__call__(
20-
*args, **kwargs
21-
)
20+
cls._instances[cls] = super().__call__(*args, **kwargs)
2221
return cls._instances[cls]
2322

2423

2524
class Logger(metaclass=Singleton):
26-
def __init__(self, log_lvl=LogLevel.INFO):
25+
def __init__(self, log_lvl: LogLevel = LogLevel.INFO) -> None:
2726
self._log = logging.getLogger("selenium")
2827
self._log.setLevel(LogLevel.DEBUG.value)
29-
30-
formatter = logging.Formatter(
31-
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
32-
)
3328
self.log_file = self._create_log_file()
34-
self._configure_logging(log_lvl, formatter)
29+
self._initialize_logging(log_lvl)
3530

36-
def _create_log_file(self):
31+
def _create_log_file(self) -> str:
3732
current_time = time.strftime("%Y-%m-%d")
3833
log_directory = os.path.abspath(
39-
os.path.join(os.path.dirname(__file__), "../tests", "logs")
40-
)
34+
os.path.join(os.path.dirname(__file__), "../tests/logs"))
4135

42-
if not os.path.exists(log_directory):
43-
os.makedirs(log_directory)
36+
try:
37+
os.makedirs(log_directory, exist_ok=True) # Create directory if it doesn't exist
38+
except Exception as e:
39+
raise RuntimeError(f"Failed to create log directory '{log_directory}': {e}")
4440

4541
return os.path.join(log_directory, f"log_{current_time}.log")
4642

47-
def _configure_logging(self, log_lvl, formatter):
43+
def _initialize_logging(self, log_lvl: LogLevel) -> None:
44+
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
4845
fh = logging.FileHandler(self.log_file, mode="w")
4946
fh.setFormatter(formatter)
5047
fh.setLevel(log_lvl.value)
5148
self._log.addHandler(fh)
5249

53-
def get_instance(self):
50+
def get_instance(self) -> logging.Logger:
5451
return self._log
52+
53+
def annotate(self, message: str, level: Literal["info", "warn", "debug", "error"]) -> None:
54+
"""Log a message at the specified level."""
55+
if level == "info":
56+
self._log.info(message)
57+
elif level == "warn":
58+
self._log.warning(message)
59+
elif level == "debug":
60+
self._log.debug(message)
61+
elif level == "error":
62+
self._log.error(message)
63+
else:
64+
raise ValueError(f"Invalid log level: {level}")
65+
66+
67+
def log(level: Literal["info", "warn", "debug", "error"] = "info") -> Callable:
68+
"""Decorator to log the current method's execution.
69+
70+
:param level: Level of the logs, e.g., info, warn, debug, error.
71+
"""
72+
logger_instance = Logger() # Get the singleton instance of Logger
73+
74+
def decorator(func: Callable) -> Callable:
75+
def wrapper(self, *args, **kwargs) -> Any:
76+
result = func(self, *args, **kwargs)
77+
method_name = f" Method :: {func.__name__}()"
78+
method_docs = format_method_doc_str(func.__doc__)
79+
80+
logs = method_docs + method_name if method_docs else f"Executed {func.__name__}()"
81+
logger_instance.annotate(logs, level)
82+
return result
83+
84+
return wrapper
85+
86+
return decorator
87+
88+
89+
def format_method_doc_str(doc_str: Optional[str]) -> Optional[str]:
90+
"""Add a dot to the docs string if it doesn't exist."""
91+
if doc_str and not doc_str.endswith('.'):
92+
return doc_str + "."
93+
return doc_str

0 commit comments

Comments
 (0)