Skip to content
Merged
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
95 changes: 58 additions & 37 deletions tests/e2e-test/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,100 +1,121 @@
import os
import atexit
"""
Pytest configuration for browser-based testing with Playwright and HTML report customization.
"""

import io
from bs4 import BeautifulSoup
import pytest
import atexit
import logging
from config.constants import URL
from pathlib import Path
from venv import logger

import pytest
from bs4 import BeautifulSoup
from playwright.sync_api import sync_playwright

from config.constants import URL

# Global dictionary to store log streams for each test
LOG_STREAMS = {}


@pytest.fixture(scope="session")
def login_logout():
# perform login and browser close once in a session
with sync_playwright() as p:
browser = p.chromium.launch(headless=False, args=["--start-maximized"])
"""
Fixture to launch the browser, log in, and yield the page object.
Closes the browser after the session ends.
"""
with sync_playwright() as playwright:
browser = playwright.chromium.launch(headless=False, args=["--start-maximized"])
context = browser.new_context(no_viewport=True)
context.set_default_timeout(80000)
page = context.new_page()
# Navigate to the login URL

page.goto(URL, wait_until="domcontentloaded")
# login to web url with username and password

# Uncomment and complete the following to enable login
# login_page = LoginPage(page)
# load_dotenv()
# login_page.authenticate(os.getenv('user_name'), os.getenv('pass_word'))
# login_page.authenticate(os.getenv("user_name"), os.getenv("pass_word"))

yield page
# perform close the browser

browser.close()

log_streams = {}

@pytest.hookimpl(tryfirst=True)
def pytest_runtest_setup(item):
# Prepare StringIO for capturing logs
"""
Pytest hook to set up a log capture for each test.
"""
stream = io.StringIO()
handler = logging.StreamHandler(stream)
handler.setLevel(logging.INFO)

logger = logging.getLogger()
logger.addHandler(handler)

# Save handler and stream
log_streams[item.nodeid] = (handler, stream)
LOG_STREAMS[item.nodeid] = (handler, stream)


@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
"""
Pytest hook to add captured logs to the test report.
"""
outcome = yield
report = outcome.get_result()

handler, stream = log_streams.get(item.nodeid, (None, None))
handler, stream = LOG_STREAMS.get(item.nodeid, (None, None))

if handler and stream:
# Make sure logs are flushed
handler.flush()
log_output = stream.getvalue()

# Only remove the handler, don't close the stream yet
logger = logging.getLogger()
logger.removeHandler(handler)

# Store the log output on the report object for HTML reporting
report.description = f"<pre>{log_output.strip()}</pre>"

# Clean up references
log_streams.pop(item.nodeid, None)
LOG_STREAMS.pop(item.nodeid, None)
else:
report.description = ""


def pytest_collection_modifyitems(items):
"""
Modify test node IDs based on the test's parameterized 'prompt' value.
"""
for item in items:
if hasattr(item, 'callspec'):
if hasattr(item, "callspec"):
prompt = item.callspec.params.get("prompt")
if prompt:
item._nodeid = prompt # This controls how the test name appears in the report
item._nodeid = prompt


def rename_duration_column():
report_path = os.path.abspath("report.html") # or your report filename
if not os.path.exists(report_path):
print("Report file not found, skipping column rename.")
"""
Modify the HTML report to rename 'Duration' column to 'Execution Time'.
Runs automatically after the test session.
"""
report_path = Path("report.html")
if not report_path.exists():
logger.info("Report file not found, skipping column rename.")
return

with open(report_path, 'r', encoding='utf-8') as f:
soup = BeautifulSoup(f, 'html.parser')
with report_path.open("r", encoding="utf-8") as file:
soup = BeautifulSoup(file, "html.parser")

# Find and rename the header
headers = soup.select('table#results-table thead th')
headers = soup.select("table#results-table thead th")
for th in headers:
if th.text.strip() == 'Duration':
th.string = 'Execution Time'
#print("Renamed 'Duration' to 'Execution Time'")
if th.text.strip() == "Duration":
th.string = "Execution Time"
break
else:
print("'Duration' column not found in report.")

with open(report_path, 'w', encoding='utf-8') as f:
f.write(str(soup))
with report_path.open("w", encoding="utf-8") as file:
file.write(str(soup))


# Register this function to run after everything is done
# Register HTML report column modification
atexit.register(rename_duration_column)
66 changes: 46 additions & 20 deletions tests/e2e-test/tests/test_contentProcessing_gp_tc.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,49 @@
import logging
import time
import pytest
from pages.HomePage import HomePage

logger = logging.getLogger(__name__)

# Define step-wise test actions for Golden Path
golden_path_steps = [
("Validate home page is loaded", lambda home: home.validate_home_page()),
("Select Invoice Schema", lambda home: home.select_schema("Invoice")),
("Select Invoice Schema", lambda home: home.select_schema("Invoice")),
("Upload Invoice documents", lambda home: home.upload_files("Invoice")),
("Refresh page till status is updated to Completed", lambda home: home.refresh()),
("Validate extracted result for Invoice", lambda home: home.validate_invoice_extracted_result()),
("Modify Extracted Data JSON & submit comments", lambda home: home.modify_and_submit_extracted_data()),
("Refreshing the page until the 'Invoice' file status is updated to 'Completed'", lambda home: home.refresh()),
(
"Validate extracted result for Invoice",
lambda home: home.validate_invoice_extracted_result(),
),
(
"Modify Extracted Data JSON & submit comments",
lambda home: home.modify_and_submit_extracted_data(),
),
("Validate process steps for Invoice", lambda home: home.validate_process_steps()),
("Select Property Loss Damage Claim Form Schema", lambda home: home.select_schema("Property")),
("Upload Property Loss Damage Claim Form documents", lambda home: home.upload_files("Property")),
("Refresh page till status is updated to Completed", lambda home: home.refresh()),
("Validate extracted result for Property Loss Damage Claim Form", lambda home: home.validate_property_extracted_result()),
("Validate process steps for Property Loss Damage Claim Form", lambda home: home.validate_process_steps()),
("Validate Delete files", lambda home: home.delete_files())
(
"Select Property Loss Damage Claim Form Schema",
lambda home: home.select_schema("Property"),
),
(
"Upload Property Loss Damage Claim Form documents",
lambda home: home.upload_files("Property"),
),
("Refreshing the page until the 'Claim Form' status is updated to 'Completed'", lambda home: home.refresh()),
(
"Validate extracted result for Property Loss Damage Claim Form",
lambda home: home.validate_property_extracted_result(),
),
(
"Validate process steps for Property Loss Damage Claim Form",
lambda home: home.validate_process_steps(),
),
("Validate user able to delete file", lambda home: home.delete_files()),
]

# Generate readable test step IDs
golden_path_ids = [f"{i+1:02d}. {desc}" for i, (desc, _) in enumerate(golden_path_steps)]
golden_path_ids = [
f"{i+1:02d}. {desc}" for i, (desc, _) in enumerate(golden_path_steps)
]


@pytest.mark.parametrize("description, action", golden_path_steps, ids=golden_path_ids)
Expand All @@ -31,16 +52,21 @@ def test_content_processing_steps(login_logout, description, action, request):
Executes Golden Path content processing steps with individual log entries.
"""
request.node._nodeid = description

page = login_logout
home = HomePage(page)

logger.info(f"Running test step: {description}")

start_time = time.time()
try:
action(home)
except Exception as e:
logger.error(f"Step failed: {description}")
duration = time.time() - start_time
message = "Step passed: %s (Duration: %.2f seconds)" % (description, duration)
logger.info(message)
request.node._report_sections.append(("call", "log", message))

except Exception:
duration = time.time() - start_time
logger.error("Step failed: %s (Duration: %.2f seconds)", description, duration, exc_info=True)
raise

# Optionally attach to report
request.node._report_sections.append(("call", "log", f"Step passed: {description}"))
Loading