Files
html/tests/pw-nonreg.py
2026-04-12 22:57:03 +02:00

257 lines
11 KiB
Python

#!/usr/bin/env python3
"""
WEVAL Playwright NonReg — visual regression + JS error detection
Outputs JSON for consumption by nonreg-api.php
Tests: WEVADS IA, Homepage, OpenClaw, Ethica, DeerFlow, WEVIA
"""
import json, sys, time
try:
from playwright.sync_api import sync_playwright
except ImportError:
print(json.dumps({"error": "playwright not installed"}))
sys.exit(1)
results = []
def test(name, fn):
t0 = time.time()
try:
detail = fn()
results.append({"name": name, "status": "PASS", "ms": round((time.time()-t0)*1000), "detail": detail})
except Exception as e:
results.append({"name": name, "status": "FAIL", "ms": round((time.time()-t0)*1000), "detail": str(e)[:200]})
with sync_playwright() as p:
browser = p.chromium.launch(headless=True, args=['--no-sandbox','--disable-dev-shm-usage'])
# ═══ WEVADS IA — the critical one (black screen regression) ═══
def test_wevads():
ctx = browser.new_context(viewport={"width": 1280, "height": 800}, ignore_https_errors=True)
page = ctx.new_page()
js_errors = []
page.on("pageerror", lambda e: js_errors.append(str(e)[:100]))
page.goto("https://weval-consulting.com/wevads-ia/", wait_until="networkidle", timeout=15000)
time.sleep(2)
# Check sidebar visible
sb = page.evaluate("() => { const el = document.querySelector('.sidebar, [class*=sidebar], #sidebar, nav'); return el ? getComputedStyle(el).display : 'NOT_FOUND'; }")
# Check main content visible
ma = page.evaluate("() => { const el = document.querySelector('.main, [class*=main], main, #main, .content'); return el ? getComputedStyle(el).display : 'NOT_FOUND'; }")
# Check key functions exist
go_fn = page.evaluate("() => typeof window.go === 'function'")
enter_fn = page.evaluate("() => typeof window.enter === 'function'")
dollar_fn = page.evaluate("() => typeof window.$ === 'function'")
ctx.close()
if js_errors:
raise Exception(f"{len(js_errors)} JS errors: {js_errors[0]}")
parts = []
if sb not in ['none','NOT_FOUND']: parts.append(f"SB={sb}")
else: raise Exception(f"sidebar display={sb}")
if ma not in ['none','NOT_FOUND']: parts.append(f"MA={ma}")
else: raise Exception(f"main display={ma}")
parts.append(f"go={'Y' if go_fn else 'N'}")
parts.append(f"enter={'Y' if enter_fn else 'N'}")
parts.append(f"$={'Y' if dollar_fn else 'N'}")
parts.append(f"JS_errors=0")
return ", ".join(parts)
test("PW WEVADS-IA dashboard", test_wevads)
# ═══ HOMEPAGE ═══
def test_homepage():
ctx = browser.new_context(viewport={"width": 1280, "height": 800}, ignore_https_errors=True)
page = ctx.new_page()
js_errors = []
page.on("pageerror", lambda e: js_errors.append(str(e)[:100]))
page.goto("https://weval-consulting.com/", wait_until="networkidle", timeout=15000)
title = page.title()
hero = page.query_selector("h1, .hero, [class*=hero]")
ctx.close()
if js_errors: raise Exception(f"{len(js_errors)} JS errors")
return f"title={title[:40]}, hero={'Y' if hero else 'N'}, JS=0"
test("PW Homepage", test_homepage)
# ═══ OPENCLAW ═══
def test_openclaw():
ctx = browser.new_context(viewport={"width": 1280, "height": 800}, ignore_https_errors=True)
page = ctx.new_page()
js_errors = []
page.on("pageerror", lambda e: js_errors.append(str(e)[:100]))
page.goto("https://weval-consulting.com/openclaw.html", wait_until="networkidle", timeout=15000)
time.sleep(1)
sidebar = page.query_selector(".sidebar, [class*=sidebar]")
providers = page.evaluate("() => document.querySelectorAll('.provider-btn, [class*=provider]').length")
ctx.close()
if js_errors: raise Exception(f"{len(js_errors)} JS errors")
return f"sidebar={'Y' if sidebar else 'N'}, providers={providers}, JS=0"
test("PW OpenClaw", test_openclaw)
# ═══ ETHICA ═══
def test_ethica():
ctx = browser.new_context(viewport={"width": 1280, "height": 800}, ignore_https_errors=True)
page = ctx.new_page()
js_errors = []
page.on("pageerror", lambda e: js_errors.append(str(e)[:100]))
page.goto("https://ethica.wevup.app/ethica-app-v3.html", wait_until="networkidle", timeout=15000)
title = page.title()
ctx.close()
if js_errors: raise Exception(f"{len(js_errors)} JS errors")
return f"title={title[:40]}, JS=0"
test("PW Ethica dashboard", test_ethica)
# ═══ DEERFLOW ═══
def test_deerflow():
ctx = browser.new_context(viewport={"width": 1280, "height": 800}, ignore_https_errors=True)
page = ctx.new_page()
js_errors = []
page.on("pageerror", lambda e: js_errors.append(str(e)[:100]))
resp = page.goto("https://weval-consulting.com/deerflow/", wait_until="networkidle", timeout=15000)
ctx.close()
if resp.status >= 400: raise Exception(f"HTTP {resp.status}")
return f"HTTP {resp.status}, JS_errors={len(js_errors)}"
test("PW DeerFlow", test_deerflow)
# ═══ CRONS MONITOR ═══
def test_monitor():
ctx = browser.new_context(viewport={"width": 1280, "height": 800}, ignore_https_errors=True)
page = ctx.new_page()
js_errors = []
page.on("pageerror", lambda e: js_errors.append(str(e)[:100]))
page.goto("https://weval-consulting.com/crons-monitor.html", wait_until="networkidle", timeout=15000)
time.sleep(1)
tabs = page.evaluate("() => document.querySelectorAll('.tab').length")
ctx.close()
if js_errors: raise Exception(f"{len(js_errors)} JS errors")
return f"tabs={tabs}, JS=0"
test("PW Crons Monitor", test_monitor)
# ═══ CRM ═══
def test_crm():
ctx = browser.new_context(viewport={"width": 1280, "height": 800}, ignore_https_errors=True)
page = ctx.new_page()
js_errors = []
page.on("pageerror", lambda e: js_errors.append(str(e)[:100]))
page.goto("https://weval-consulting.com/crm.html", wait_until="networkidle", timeout=15000)
ctx.close()
if js_errors: raise Exception(f"{len(js_errors)} JS errors")
return f"JS=0"
test("PW CRM", test_crm)
# ═══ WEVIA WIDGET ═══
def test_widget():
ctx = browser.new_context(viewport={"width": 1280, "height": 800}, ignore_https_errors=True)
page = ctx.new_page()
js_errors = []
page.on("pageerror", lambda e: js_errors.append(str(e)[:100]))
page.goto("https://weval-consulting.com/wevia-widget.html", wait_until="networkidle", timeout=15000)
input_el = page.query_selector("input, textarea, [contenteditable]")
ctx.close()
if js_errors: raise Exception(f"{len(js_errors)} JS errors")
return f"input={'Y' if input_el else 'N'}, JS=0"
test("PW WEVIA Widget", test_widget)
# ═══ NODE --CHECK on WEVADS SPA (JS syntax) ═══
def test_node_check():
import subprocess
# Download the SPA and extract JS
r = subprocess.run(["node", "--check", "/var/www/html/wevads-ia/index.html"],
capture_output=True, text=True, timeout=10)
# node --check won't work on HTML, so extract inline JS
import re
html = open("/var/www/html/wevads-ia/index.html").read()
scripts = re.findall(r'<script[^>]*>(.*?)</script>', html, re.DOTALL)
total_js = sum(len(s) for s in scripts)
# Write combined JS to temp file
combined = "\n".join(scripts)
with open("/tmp/wevads-check.js", "w") as f:
f.write(combined)
r = subprocess.run(["node", "--check", "/tmp/wevads-check.js"],
capture_output=True, text=True, timeout=10)
if r.returncode != 0:
raise Exception(f"Syntax error: {r.stderr[:150]}")
return f"0 syntax errors, {len(scripts)} scripts, {total_js} chars"
test("PW WEVADS node --check", test_node_check)
# ═══ 502 REGRESSION TESTS — SSO protected routes ═══
def test_wevia_cyber():
ctx = browser.new_context(viewport={"width": 1280, "height": 800}, ignore_https_errors=True)
page = ctx.new_page()
resp = page.goto("https://weval-consulting.com/wevia-cyber", wait_until="networkidle", timeout=15000)
status = resp.status
ctx.close()
# 302 = SSO redirect (OK), 502 = REGRESSION!
if status == 502: raise Exception("502 Bad Gateway REGRESSION!")
if status == 503: raise Exception("503 Service Unavailable!")
return f"HTTP {status} (SSO redirect OK)"
test("PW wevia-cyber (502 guard)", test_wevia_cyber)
def test_wevia_monitor():
ctx = browser.new_context(viewport={"width": 1280, "height": 800}, ignore_https_errors=True)
page = ctx.new_page()
resp = page.goto("https://weval-consulting.com/wevia-monitor", wait_until="networkidle", timeout=15000)
status = resp.status
ctx.close()
if status == 502: raise Exception("502 Bad Gateway REGRESSION!")
if status == 503: raise Exception("503 Service Unavailable!")
return f"HTTP {status} (SSO redirect OK)"
test("PW wevia-monitor (502 guard)", test_wevia_monitor)
def test_wevia_go_live():
ctx = browser.new_context(viewport={"width": 1280, "height": 800}, ignore_https_errors=True)
page = ctx.new_page()
resp = page.goto("https://weval-consulting.com/wevia-go-live.html", wait_until="networkidle", timeout=15000)
status = resp.status
ctx.close()
if status >= 500: raise Exception(f"HTTP {status} SERVER ERROR!")
return f"HTTP {status}"
test("PW wevia-go-live (502 guard)", test_wevia_go_live)
# ═══ TEST REPORT PAGES — ensure they load ═══
def test_nonreg_dashboard():
ctx = browser.new_context(viewport={"width": 1280, "height": 800}, ignore_https_errors=True)
page = ctx.new_page()
js_errors = []
page.on("pageerror", lambda e: js_errors.append(str(e)[:100]))
page.goto("https://weval-consulting.com/test-report/full-nonreg-dashboard.html", wait_until="networkidle", timeout=15000)
ctx.close()
if js_errors: raise Exception(f"{len(js_errors)} JS errors")
return f"JS=0"
test("PW NonReg Dashboard", test_nonreg_dashboard)
def test_visual_proof():
ctx = browser.new_context(viewport={"width": 1280, "height": 800}, ignore_https_errors=True)
page = ctx.new_page()
page.goto("https://weval-consulting.com/test-report/visual-proof-report.html", wait_until="networkidle", timeout=15000)
images = page.evaluate("() => document.querySelectorAll('img').length")
ctx.close()
return f"{images} images loaded"
test("PW Visual Proof Report", test_visual_proof)
browser.close()
passed = sum(1 for r in results if r["status"] == "PASS")
failed = len(results) - passed
print(json.dumps({
"pass": passed,
"fail": failed,
"total": len(results),
"tests": results
}))