from start import Project class TesterAgent: """Агент-тестировщик: открывает браузер, проверяет консоль на ошибки.""" @staticmethod def test(project: Project) -> List[Dict[str, Any]]: print(f"🌐 Тестировщик проверяет {project.url} ...") errors = [] try: with sync_playwright() as p: browser = p.chromium.launch(headless=True) context = browser.new_context() page = context.new_page() console_errors = [] # Перехват ошибок страницы (даёт объект Error) def handle_pageerror(error): error_info = { "message": str(error), "type": "pageerror", "location": None, "stack": error.stack if hasattr(error, 'stack') else None } # Извлекаем location из стека, если есть if error_info["stack"]: import re # Ищем строки вида at ... (file:line:col) match = re.search(r'at .*?\((.*?):(\d+):(\d+)\)', error_info["stack"]) if match: file_path = match.group(1) line = int(match.group(2)) col = int(match.group(3)) error_info["location"] = {"url": file_path, "line": line, "column": col} console_errors.append(error_info) page.on("pageerror", handle_pageerror) # Обработка console сообщений def handle_console(msg): if msg.type in ("error", "warning"): error_info = { "message": msg.text, "type": msg.type, "location": None, "stack": None } # Местоположение (уже есть) if hasattr(msg, 'location') and msg.location: error_info["location"] = { "url": msg.location.get("url", ""), "line": msg.location.get("lineNumber", 0), "column": msg.location.get("columnNumber", 0) } # Попытка извлечь стек из сообщения (часто в конце сообщения есть строки at) if error_info["message"]: import re # Ищем строки, начинающиеся с 'at ' (стек) stack_lines = re.findall(r'at .*', error_info["message"]) if stack_lines: error_info["stack"] = "\n".join(stack_lines) else: # В некоторых браузерах стек может быть в конце сообщения после \n parts = error_info["message"].split('\n') if len(parts) > 1: # Проверяем, есть ли строки, начинающиеся с 'at' stack_candidate = "\n".join( [line for line in parts if line.strip().startswith('at')]) if stack_candidate: error_info["stack"] = stack_candidate console_errors.append(error_info) page.on("console", handle_console) # Внедряем скрипт для перехвата необработанных ошибок и rejection (чтобы они попали в console) page.add_init_script(""" window.addEventListener('error', function(e) { console.error(e.message + '\\n' + e.stack); }); window.addEventListener('unhandledrejection', function(e) { console.error(e.reason.message || e.reason); }); """) page.goto(project.url, timeout=30000, wait_until='load') time.sleep(2) browser.close() if console_errors: errors = console_errors else: print(" ✅ Ошибок в консоли не обнаружено.") except Exception as e: errors.append({ "message": f"Ошибка запуска браузера: {e}", "type": "error", "location": None, "stack": None }) return errors