import pytest import os import json from tests.browser import create_chrome_driver def get_run_id(config, prefix=None): run_prefix = prefix or _get_run_prefix(config) run_ids = getattr(config, "_pxil_run_ids", {}) if run_prefix in run_ids: return run_ids[run_prefix] base_folder = os.path.join("reports", "screenshots") os.makedirs(base_folder, exist_ok=True) existing = [ name for name in os.listdir(base_folder) if name.startswith(f"{run_prefix}_") ] if not existing: next_number = 1 else: numbers = [ int(name.split("_")[-1]) for name in existing if name.split("_")[-1].isdigit() ] next_number = max(numbers, default=0) + 1 run_id = f"{run_prefix}_{next_number:03d}" run_ids[run_prefix] = run_id config._pxil_run_ids = run_ids return run_id def pytest_configure(config): run_id = get_run_id(config) if config.pluginmanager.hasplugin("html"): reports_dir = os.path.abspath(os.path.join("reports", "html")) os.makedirs(reports_dir, exist_ok=True) config.option.htmlpath = os.path.join(reports_dir, f"{run_id}.html") config.option.self_contained_html = True # ----------------------------- # WebDriver Fixture # ----------------------------- @pytest.fixture def driver(): driver = create_chrome_driver() driver.maximize_window() yield driver driver.quit() # ----------------------------- # Generate Incremental Test ID # ----------------------------- @pytest.fixture def test_context(request): test_id = get_run_id(request.config, _setup_item_prefix(request.node)) test_name = request.node.name folder = os.path.abspath( os.path.join("reports", "screenshots", test_id, test_name) ) log_folder = os.path.abspath( os.path.join("reports", "logs", test_id, test_name) ) os.makedirs(folder, exist_ok=True) os.makedirs(log_folder, exist_ok=True) print(f"\nTEST ID: {test_id}") return { "test_id": test_id, "folder": folder, "log_folder": log_folder, "steps": [], "extra_folders": [], } # ----------------------------- # Attach Screenshot Folder Link # ----------------------------- @pytest.hookimpl(hookwrapper=True) def pytest_runtest_makereport(item, call): outcome = yield report = outcome.get_result() if report.when == "call": context = item.funcargs.get("test_context", None) if context: folder = context["folder"] steps = context.get("steps", []) if report.failed: driver = item.funcargs.get("driver", None) failure_index = len(steps) + 1 failure_name = "failure_state" failure_filename = f"{failure_index:02d}_{failure_name}.png" failure_path = os.path.join(folder, failure_filename) if driver: try: driver.save_screenshot(failure_path) steps.append( { "index": failure_index, "name": failure_name, "path": failure_path, "status": "failed", } ) except Exception: pass if item.config.pluginmanager.hasplugin("html"): from pytest_html import extras extras_list = getattr(report, "extras", []) for step in steps: extras_list.append( extras.url( _as_file_url(step["path"]), name=f"Step {step['index']:02d} [{step['status']}] {step['name']}" ) ) if steps: extras_list.append( extras.html(_build_steps_html(steps)) ) extras_list.append( extras.url(_as_file_url(folder), name="Screenshots Folder") ) log_folder = context.get("log_folder") if log_folder: extras_list.append( extras.url(_as_file_url(log_folder), name="Logs Folder") ) for extra_folder in context.get("extra_folders", []): extras_list.append( extras.url( _as_file_url(extra_folder["path"]), name=extra_folder["name"] ) ) report.extras = extras_list def _as_file_url(path): absolute_path = os.path.abspath(path).replace("\\", "/") return f"file:///{absolute_path}" def _build_steps_html(steps): rows = [] for step in steps: step_url = _as_file_url(step["path"]) rows.append( "
| # | Status | Step | Screenshot |
|---|