|
4 | 4 | """ |
5 | 5 | from __future__ import annotations |
6 | 6 |
|
| 7 | +import io |
7 | 8 | import os |
8 | 9 | import subprocess |
9 | 10 | import time |
10 | 11 |
|
| 12 | +import allure |
11 | 13 | import pytest |
12 | 14 | from dogtail.tree import root |
| 15 | +from PIL import Image |
| 16 | +from Xlib import display |
| 17 | +from Xlib import X |
13 | 18 |
|
14 | 19 | from accessible_constant import DEFAULT_WALLET_MODES |
15 | 20 | from src.model.enums.enums_model import WalletType |
@@ -132,6 +137,82 @@ def pytest_runtest_logreport(report): |
132 | 137 | _print_test_result('⏭️', 'SKIPPED', test_name) |
133 | 138 |
|
134 | 139 |
|
| 140 | +def _capture_screenshot(): |
| 141 | + """ |
| 142 | + Capture a screenshot of the entire screen using Xlib. |
| 143 | +
|
| 144 | + Returns: |
| 145 | + bytes: PNG image data, or None if capture fails |
| 146 | + """ |
| 147 | + try: |
| 148 | + # Get the display and screen |
| 149 | + dpy = display.Display() |
| 150 | + screen = dpy.screen() |
| 151 | + root_window = screen.root |
| 152 | + |
| 153 | + # Get screen dimensions |
| 154 | + width = screen.width_in_pixels |
| 155 | + height = screen.height_in_pixels |
| 156 | + |
| 157 | + # Capture the screen |
| 158 | + raw_image = root_window.get_image( |
| 159 | + 0, 0, width, height, X.ZPixmap, 0xffffffff, |
| 160 | + ) |
| 161 | + |
| 162 | + # Convert to PIL Image |
| 163 | + image = Image.frombytes( |
| 164 | + 'RGB', |
| 165 | + (width, height), |
| 166 | + raw_image.data, |
| 167 | + 'raw', |
| 168 | + 'BGRX', |
| 169 | + ) |
| 170 | + |
| 171 | + # Save to bytes buffer |
| 172 | + buffer = io.BytesIO() |
| 173 | + image.save(buffer, format='PNG') |
| 174 | + buffer.seek(0) |
| 175 | + |
| 176 | + return buffer.getvalue() |
| 177 | + except Exception as e: |
| 178 | + print(f"[SCREENSHOT] Failed to capture screenshot: {e}") |
| 179 | + return None |
| 180 | + |
| 181 | + |
| 182 | +@pytest.hookimpl(tryfirst=True, hookwrapper=True) |
| 183 | +def pytest_runtest_makereport(item): |
| 184 | + """ |
| 185 | + Pytest hook to capture screenshots on test failure and attach to Allure report. |
| 186 | +
|
| 187 | + This hook runs after each test phase (setup, call, teardown) and captures |
| 188 | + a screenshot if the test failed during the 'call' phase. |
| 189 | + """ |
| 190 | + # Execute all other hooks to obtain the report object |
| 191 | + outcome = yield |
| 192 | + report = outcome.get_result() |
| 193 | + |
| 194 | + # Only capture screenshot on test failure during the 'call' phase |
| 195 | + if report.when == 'call' and report.failed: |
| 196 | + try: |
| 197 | + screenshot_bytes = _capture_screenshot() |
| 198 | + |
| 199 | + if screenshot_bytes: |
| 200 | + # Attach screenshot to Allure report |
| 201 | + allure.attach( |
| 202 | + screenshot_bytes, |
| 203 | + name='failure_screenshot', |
| 204 | + attachment_type=allure.attachment_type.PNG, |
| 205 | + ) |
| 206 | + print(f"""[SCREENSHOT] ✅ Screenshot captured and attached for failed test: |
| 207 | + {item.nodeid}""") |
| 208 | + else: |
| 209 | + print(f"""[SCREENSHOT] ⚠️ Failed to capture screenshot for: |
| 210 | + {item.nodeid}""") |
| 211 | + except Exception as e: |
| 212 | + print(f"""[SCREENSHOT] ❌ Error capturing screenshot for |
| 213 | + {item.nodeid}: {e}""") |
| 214 | + |
| 215 | + |
135 | 216 | def _is_ci_environment(): |
136 | 217 | """Check if running in CI environment.""" |
137 | 218 | return os.getenv('CI', '').lower() in ('true', '1', 'yes') |
|
0 commit comments