""" 🤖 Fagun Browser Automation Testing Agent - Screenshot Capture ============================================================== Screenshot capture utilities for testing reports and documentation. Author: Mejbaur Bahar Fagun Role: Software Engineer in Test LinkedIn: https://www.linkedin.com/in/mejbaur/ """ import os import base64 from datetime import datetime from pathlib import Path from typing import Optional, Dict, Any from playwright.async_api import Page import logging logger = logging.getLogger(__name__) class ScreenshotCapture: """Handles screenshot capture during test execution.""" def __init__(self, output_dir: str = "screenshots"): self.output_dir = Path(output_dir) self.output_dir.mkdir(exist_ok=True) self.screenshots = [] async def capture_screenshot( self, page: Page, description: str = "Test Screenshot", full_page: bool = True ) -> Dict[str, Any]: """ Capture a screenshot of the current page. Args: page: Playwright page object description: Description of the screenshot full_page: Whether to capture full page or viewport only Returns: Dictionary containing screenshot metadata """ try: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")[:-3] filename = f"screenshot_{timestamp}.png" filepath = self.output_dir / filename # Capture screenshot if full_page: await page.screenshot(path=str(filepath), full_page=True) else: await page.screenshot(path=str(filepath), full_page=False) # Get page info url = page.url title = await page.title() screenshot_data = { "filename": filename, "path": str(filepath), "description": description, "timestamp": datetime.now().isoformat(), "url": url, "title": title, "full_page": full_page } self.screenshots.append(screenshot_data) logger.info(f"Screenshot captured: {filename}") return screenshot_data except Exception as e: logger.error(f"Error capturing screenshot: {str(e)}") return { "filename": None, "path": None, "description": description, "timestamp": datetime.now().isoformat(), "url": page.url if page else "Unknown", "title": "Error", "full_page": full_page, "error": str(e) } async def capture_element_screenshot( self, page: Page, selector: str, description: str = "Element Screenshot" ) -> Dict[str, Any]: """ Capture a screenshot of a specific element. Args: page: Playwright page object selector: CSS selector for the element description: Description of the screenshot Returns: Dictionary containing screenshot metadata """ try: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")[:-3] filename = f"element_{timestamp}.png" filepath = self.output_dir / filename # Wait for element to be visible element = await page.wait_for_selector(selector, timeout=5000) # Capture element screenshot await element.screenshot(path=str(filepath)) screenshot_data = { "filename": filename, "path": str(filepath), "description": f"{description} - Element: {selector}", "timestamp": datetime.now().isoformat(), "url": page.url, "title": await page.title(), "selector": selector, "type": "element" } self.screenshots.append(screenshot_data) logger.info(f"Element screenshot captured: {filename}") return screenshot_data except Exception as e: logger.error(f"Error capturing element screenshot: {str(e)}") return { "filename": None, "path": None, "description": f"{description} - Element: {selector}", "timestamp": datetime.now().isoformat(), "url": page.url if page else "Unknown", "title": "Error", "selector": selector, "type": "element", "error": str(e) } async def capture_error_screenshot( self, page: Page, error_message: str, description: str = "Error Screenshot" ) -> Dict[str, Any]: """ Capture a screenshot when an error occurs. Args: page: Playwright page object error_message: The error message description: Description of the screenshot Returns: Dictionary containing screenshot metadata """ try: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")[:-3] filename = f"error_{timestamp}.png" filepath = self.output_dir / filename # Capture screenshot await page.screenshot(path=str(filepath), full_page=True) screenshot_data = { "filename": filename, "path": str(filepath), "description": f"{description} - Error: {error_message[:50]}...", "timestamp": datetime.now().isoformat(), "url": page.url, "title": await page.title(), "error_message": error_message, "type": "error" } self.screenshots.append(screenshot_data) logger.info(f"Error screenshot captured: {filename}") return screenshot_data except Exception as e: logger.error(f"Error capturing error screenshot: {str(e)}") return { "filename": None, "path": None, "description": f"{description} - Error: {error_message[:50]}...", "timestamp": datetime.now().isoformat(), "url": page.url if page else "Unknown", "title": "Error", "error_message": error_message, "type": "error", "error": str(e) } def get_screenshots(self) -> list: """Get all captured screenshots.""" return self.screenshots def clear_screenshots(self): """Clear the screenshots list.""" self.screenshots = [] def get_screenshot_summary(self) -> Dict[str, Any]: """Get a summary of captured screenshots.""" total_screenshots = len(self.screenshots) successful_screenshots = len([s for s in self.screenshots if s.get('filename')]) error_screenshots = len([s for s in self.screenshots if s.get('type') == 'error']) element_screenshots = len([s for s in self.screenshots if s.get('type') == 'element']) return { "total_screenshots": total_screenshots, "successful_screenshots": successful_screenshots, "error_screenshots": error_screenshots, "element_screenshots": element_screenshots, "screenshots": self.screenshots } def save_screenshots_metadata(self, filepath: str): """Save screenshots metadata to a JSON file.""" try: metadata = { "capture_time": datetime.now().isoformat(), "total_screenshots": len(self.screenshots), "screenshots": self.screenshots } with open(filepath, 'w') as f: import json json.dump(metadata, f, indent=2) logger.info(f"Screenshots metadata saved to: {filepath}") except Exception as e: logger.error(f"Error saving screenshots metadata: {str(e)}") # Global screenshot capture instance screenshot_capture = ScreenshotCapture() async def capture_test_screenshot( page: Page, test_name: str, step_description: str = "Test Step" ) -> Dict[str, Any]: """ Convenience function to capture a test screenshot. Args: page: Playwright page object test_name: Name of the test step_description: Description of the test step Returns: Dictionary containing screenshot metadata """ description = f"{test_name} - {step_description}" return await screenshot_capture.capture_screenshot(page, description) async def capture_error_screenshot( page: Page, test_name: str, error_message: str ) -> Dict[str, Any]: """ Convenience function to capture an error screenshot. Args: page: Playwright page object test_name: Name of the test error_message: The error message Returns: Dictionary containing screenshot metadata """ description = f"{test_name} - Error" return await screenshot_capture.capture_error_screenshot(page, error_message, description)