101 lines
5.1 KiB
Python
101 lines
5.1 KiB
Python
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 |