Skip to content

Commit 1220cf9

Browse files
test: MACAE-Implemented Log execution time per prompt in Report
2 parents ba50c3e + 43288a0 commit 1220cf9

File tree

5 files changed

+166
-62
lines changed

5 files changed

+166
-62
lines changed

tests/e2e-test/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ This will create a virtual environment directory named microsoft inside your cur
2020
Installing Playwright Pytest from Virtual Environment
2121

2222
- To install libraries run "pip install -r requirements.txt"
23-
- Install the required browsers "playwright install"
23+
2424

2525
Run test cases
2626

27-
- To run test cases from your 'tests' folder : "pytest --headed --html=report/report.html"
27+
- To run test cases from your 'tests/e2e-test' folder : "pytest --html=report.html --self-contained-html"
2828

2929
Create .env file in project root level with web app url and client credentials
3030

tests/e2e-test/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ python-dotenv
44
pytest-check
55
pytest-html
66
py
7+
beautifulsoup4

tests/e2e-test/tests/conftest.py

Lines changed: 80 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1-
import os
2-
1+
from pathlib import Path
32
import pytest
4-
from config.constants import URL
53
from playwright.sync_api import sync_playwright
6-
from py.xml import html # type: ignore
4+
from config.constants import *
5+
from slugify import slugify
6+
from pages.loginPage import LoginPage
7+
from dotenv import load_dotenv
8+
import os
9+
from py.xml import html # type: ignore
10+
import io
11+
import logging
12+
from bs4 import BeautifulSoup
13+
import atexit
714

815

916
@pytest.fixture(scope="session")
@@ -17,8 +24,11 @@ def login_logout():
1724
# Navigate to the login URL
1825
page.goto(URL)
1926
# Wait for the login form to appear
20-
page.wait_for_load_state("networkidle")
21-
27+
page.wait_for_load_state('networkidle')
28+
# login to web url with username and password
29+
#login_page = LoginPage(page)
30+
#load_dotenv()
31+
#login_page.authenticate(os.getenv('user_name'),os.getenv('pass_word'))
2232
yield page
2333

2434
# perform close the browser
@@ -27,26 +37,77 @@ def login_logout():
2737

2838
@pytest.hookimpl(tryfirst=True)
2939
def pytest_html_report_title(report):
30-
report.title = "Automation_MACAE"
40+
report.title = "Test Automation MACAE"
3141

3242

33-
# Add a column for descriptions
34-
def pytest_html_results_table_header(cells):
35-
cells.insert(1, html.th("Description"))
43+
log_streams = {}
3644

45+
@pytest.hookimpl(tryfirst=True)
46+
def pytest_runtest_setup(item):
47+
# Prepare StringIO for capturing logs
48+
stream = io.StringIO()
49+
handler = logging.StreamHandler(stream)
50+
handler.setLevel(logging.INFO)
3751

38-
def pytest_html_results_table_row(report, cells):
39-
cells.insert(
40-
1, html.td(report.description if hasattr(report, "description") else "")
41-
)
52+
logger = logging.getLogger()
53+
logger.addHandler(handler)
54+
55+
# Save handler and stream
56+
log_streams[item.nodeid] = (handler, stream)
4257

4358

44-
# Add logs and docstring to report
4559
@pytest.hookimpl(hookwrapper=True)
4660
def pytest_runtest_makereport(item, call):
4761
outcome = yield
4862
report = outcome.get_result()
49-
report.description = str(item.function.__doc__)
50-
os.makedirs("logs", exist_ok=True)
51-
extra = getattr(report, "extra", [])
52-
report.extra = extra
63+
64+
handler, stream = log_streams.get(item.nodeid, (None, None))
65+
66+
if handler and stream:
67+
# Make sure logs are flushed
68+
handler.flush()
69+
log_output = stream.getvalue()
70+
71+
# Only remove the handler, don't close the stream yet
72+
logger = logging.getLogger()
73+
logger.removeHandler(handler)
74+
75+
# Store the log output on the report object for HTML reporting
76+
report.description = f"<pre>{log_output.strip()}</pre>"
77+
78+
# Clean up references
79+
log_streams.pop(item.nodeid, None)
80+
else:
81+
report.description = ""
82+
83+
def pytest_collection_modifyitems(items):
84+
for item in items:
85+
if hasattr(item, 'callspec'):
86+
prompt = item.callspec.params.get("prompt")
87+
if prompt:
88+
item._nodeid = prompt # This controls how the test name appears in the report
89+
90+
def rename_duration_column():
91+
report_path = os.path.abspath("report.html") # or your report filename
92+
if not os.path.exists(report_path):
93+
print("Report file not found, skipping column rename.")
94+
return
95+
96+
with open(report_path, 'r', encoding='utf-8') as f:
97+
soup = BeautifulSoup(f, 'html.parser')
98+
99+
# Find and rename the header
100+
headers = soup.select('table#results-table thead th')
101+
for th in headers:
102+
if th.text.strip() == 'Duration':
103+
th.string = 'Execution Time'
104+
#print("Renamed 'Duration' to 'Execution Time'")
105+
break
106+
else:
107+
print("'Duration' column not found in report.")
108+
109+
with open(report_path, 'w', encoding='utf-8') as f:
110+
f.write(str(soup))
111+
112+
# Register this function to run after everything is done
113+
atexit.register(rename_duration_column)
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import logging
2+
import time
3+
import pytest
4+
from pages.BIAB import BIABPage
5+
from config.constants import (
6+
prompt_question1,
7+
prompt_question2,
8+
rai_prompt,
9+
employee_details,
10+
product_details,
11+
)
12+
13+
logger = logging.getLogger(__name__)
14+
15+
16+
# Define test steps and prompts
17+
test_cases = [
18+
("Validate home page is loaded", lambda biab: biab.validate_home_page()),
19+
20+
(f"Verify Run Prompt 1: '{prompt_question1}' & run all stages", lambda biab: (
21+
biab.enter_a_question(prompt_question1),
22+
biab.click_send_button(),
23+
biab.click_my_task(),
24+
biab.enter_aditional_info(employee_details),
25+
# biab.click_aditional_send_button(),
26+
biab.processing_different_stage(),
27+
biab.click_new_task()
28+
)),
29+
30+
(f"Verify Run Prompt 2: '{prompt_question2}' & run all stages", lambda biab: (
31+
biab.enter_a_question(prompt_question2),
32+
biab.click_send_button(),
33+
biab.click_my_task(),
34+
biab.enter_aditional_info(product_details),
35+
# biab.click_aditional_send_button(),
36+
biab.processing_different_stage(),
37+
biab.click_new_task()
38+
)),
39+
40+
("Verify Run Prompt 3 via Quick Task - Mobile Plan Query & run all stages", lambda biab: (
41+
biab.click_mobile_plan(),
42+
biab.click_send_button(),
43+
biab.click_my_task(),
44+
biab.processing_different_stage(),
45+
biab.click_new_task()
46+
)),
47+
48+
(f"Verify Run RAI Prompt: '{rai_prompt}' to make sure task is not created and validation message is displayed.", lambda biab: (
49+
biab.enter_a_question(rai_prompt),
50+
biab.validate_rai_validation_message()
51+
)),
52+
]
53+
54+
# Create test IDs like "01. Validate home page", "02. Run Prompt 1: ..."
55+
test_ids = [f"{i+1:02d}. {case[0]}" for i, case in enumerate(test_cases)]
56+
57+
58+
@pytest.mark.parametrize("prompt, action", test_cases, ids=test_ids)
59+
def test_biab_prompt_case(login_logout, prompt, action, request):
60+
"""
61+
Each BIAB prompt runs as an individual test case with execution time logging
62+
and meaningful test step titles.
63+
"""
64+
page = login_logout
65+
biab_page = BIABPage(page)
66+
logger.info(f"Running test step: {prompt}")
67+
68+
start = time.time()
69+
if isinstance(action, tuple):
70+
for step in action:
71+
if callable(step):
72+
step()
73+
else:
74+
action(biab_page)
75+
end = time.time()
76+
77+
duration = end - start
78+
logger.info(f"Execution Time for '{prompt}': {duration:.2f}s")
79+
80+
# Attach execution time to pytest report
81+
request.node._report_sections.append((
82+
"call", "log", f"Execution time: {duration:.2f}s"
83+
))

tests/e2e-test/tests/test_poc_BIAB.py

Lines changed: 0 additions & 41 deletions
This file was deleted.

0 commit comments

Comments
 (0)