temp / instructor /checks /dynamic_checks.py
CheeksTheGeek's picture
Initial commit: LLM Code Deployment System
c5292d8 unverified
Raw
History Blame Contribute Delete
7.14 kB
"""Dynamic checks using Playwright."""
import asyncio
import json
import re
from typing import Any
from playwright.async_api import async_playwright
from shared.logger import setup_logger
logger = setup_logger(__name__)
class DynamicChecker:
"""Perform dynamic checks using Playwright."""
def __init__(self, pages_url: str, checks: list[str]) -> None:
"""Initialize dynamic checker.
Args:
pages_url: GitHub Pages URL
checks: List of check descriptions
"""
self.pages_url = pages_url
self.checks = checks
async def run_checks(self) -> list[dict[str, Any]]:
"""Run all dynamic checks.
Returns:
List of check results
"""
results = []
async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page()
try:
# Load page
await page.goto(self.pages_url, timeout=30000, wait_until="networkidle")
# Wait a bit for JS to execute
await page.wait_for_timeout(2000)
# Run each check
for check in self.checks:
result = await self._run_single_check(page, check)
results.append(result)
except Exception as e:
logger.error(f"Error loading page {self.pages_url}: {e}")
results.append(
{
"check": "Page Load",
"passed": False,
"score": 0.0,
"reason": f"Failed to load page: {e}",
}
)
finally:
await browser.close()
return results
async def _run_single_check(self, page, check_desc: str) -> dict[str, Any]:
"""Run a single check.
Args:
page: Playwright page
check_desc: Check description
Returns:
Check result
"""
try:
# Parse check type
if check_desc.startswith("js:"):
# JavaScript evaluation check
js_code = check_desc[3:].strip()
return await self._run_js_check(page, js_code)
else:
# Text-based check
return await self._run_text_check(page, check_desc)
except Exception as e:
logger.error(f"Error running check '{check_desc}': {e}")
return {
"check": check_desc,
"passed": False,
"score": 0.0,
"reason": f"Error: {e}",
}
async def _run_js_check(self, page, js_code: str) -> dict[str, Any]:
"""Run JavaScript evaluation check.
Args:
page: Playwright page
js_code: JavaScript code to evaluate
Returns:
Check result
"""
try:
result = await page.evaluate(js_code)
if isinstance(result, bool):
return {
"check": f"JS: {js_code[:50]}...",
"passed": result,
"score": 1.0 if result else 0.0,
"reason": f"JavaScript evaluated to {result}",
}
else:
return {
"check": f"JS: {js_code[:50]}...",
"passed": True,
"score": 1.0,
"reason": f"JavaScript returned: {result}",
}
except Exception as e:
return {
"check": f"JS: {js_code[:50]}...",
"passed": False,
"score": 0.0,
"reason": f"JavaScript error: {e}",
}
async def _run_text_check(self, page, check_desc: str) -> dict[str, Any]:
"""Run text-based check.
Args:
page: Playwright page
check_desc: Check description
Returns:
Check result
"""
# Extract selector and expected condition
# Examples:
# - "Page title equals 'Sales Summary xyz'"
# - "Element #total-sales exists and displays numeric value"
# - "Bootstrap 5 CSS loaded from jsdelivr"
content = await page.content()
# Check for page title
if "page title" in check_desc.lower():
title = await page.title()
match = re.search(r"['\"]([^'\"]+)['\"]", check_desc)
if match:
expected = match.group(1)
passed = expected in title
return {
"check": check_desc,
"passed": passed,
"score": 1.0 if passed else 0.0,
"reason": f"Title is '{title}', expected to contain '{expected}'",
}
# Check for element existence
if "element" in check_desc.lower():
# Extract selector
selector_match = re.search(r"(#[\w-]+|\.[a-z-]+|[a-z]+)", check_desc, re.IGNORECASE)
if selector_match:
selector = selector_match.group(1)
try:
element = await page.query_selector(selector)
if element:
text = await element.text_content()
return {
"check": check_desc,
"passed": True,
"score": 1.0,
"reason": f"Element {selector} found with content: {text[:50]}...",
}
else:
return {
"check": check_desc,
"passed": False,
"score": 0.0,
"reason": f"Element {selector} not found",
}
except Exception as e:
return {
"check": check_desc,
"passed": False,
"score": 0.0,
"reason": f"Error finding element: {e}",
}
# Check for Bootstrap/library loading
if "bootstrap" in check_desc.lower() or "cdn" in check_desc.lower():
has_bootstrap = "bootstrap" in content.lower()
return {
"check": check_desc,
"passed": has_bootstrap,
"score": 1.0 if has_bootstrap else 0.0,
"reason": f"Bootstrap {'found' if has_bootstrap else 'not found'} in page",
}
# Default: check if description keywords appear in content
keywords = re.findall(r"\b\w{4,}\b", check_desc.lower())
matches = sum(1 for kw in keywords if kw in content.lower())
score = min(matches / max(len(keywords), 1), 1.0)
return {
"check": check_desc,
"passed": score >= 0.5,
"score": score,
"reason": f"Matched {matches}/{len(keywords)} keywords",
}