fix: physical realism for 3D demo
- Load STL models with fallback to primitives - True physical scale (1 unit = 1 meter) - Sensor rig at 1.35m above max item - Roll-cages for C/D zones (1.2×0.8×0.8m) - Chutes for physical routing - HUD/overlay repositioned to avoid overlap - Added physicalLayout tests
This commit is contained in:
131
scripts/test_physical_realism.py
Normal file
131
scripts/test_physical_realism.py
Normal file
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Browser QA script for physical realism fixes.
|
||||
Takes screenshots of production to verify:
|
||||
- STL models displayed
|
||||
- Items on belt at correct scale
|
||||
- Sensors above items
|
||||
- Speed synchronized
|
||||
- Roll cages for C/D
|
||||
- No HUD/overlay overlap
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import time
|
||||
from pathlib import Path
|
||||
from playwright.async_api import async_playwright
|
||||
|
||||
BASE_URL = "https://arhipovdan.ru"
|
||||
SCREENSHOT_DIR = Path(__file__).parent.parent / "docs" / "physical_realism_fix_screenshots"
|
||||
|
||||
async def main():
|
||||
SCREENSHOT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
async with async_playwright() as p:
|
||||
browser = await p.chromium.launch(headless=True)
|
||||
|
||||
# Desktop viewport
|
||||
context = await browser.new_context(viewport={"width": 1920, "height": 1080})
|
||||
page = await context.new_page()
|
||||
|
||||
# Collect console errors
|
||||
errors = []
|
||||
page.on("console", lambda msg: errors.append(msg.text) if msg.type == "error" else None)
|
||||
|
||||
print("Loading production site...")
|
||||
await page.goto(BASE_URL, wait_until="networkidle", timeout=30000)
|
||||
await asyncio.sleep(2)
|
||||
|
||||
# Screenshot 1: Initial idle state
|
||||
print("Screenshot: initial idle state...")
|
||||
await page.screenshot(path=str(SCREENSHOT_DIR / "initial_idle.png"))
|
||||
|
||||
# Start playback
|
||||
print("Starting playback...")
|
||||
play_button = page.locator(".demo-play-btn, button:has-text('Play'), button:has-text('Запустить')")
|
||||
if await play_button.count() > 0:
|
||||
await play_button.first.click()
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
# Screenshot 2: Real STL item (after short delay for model load)
|
||||
print("Screenshot: STL item...")
|
||||
await asyncio.sleep(2)
|
||||
await page.screenshot(path=str(SCREENSHOT_DIR / "real_stl_item.png"))
|
||||
|
||||
# Screenshot 3: Item on belt scale
|
||||
print("Screenshot: item on belt scale...")
|
||||
await asyncio.sleep(1)
|
||||
await page.screenshot(path=str(SCREENSHOT_DIR / "item_on_belt_scale.png"))
|
||||
|
||||
# Screenshot 4: Sensor above item
|
||||
print("Screenshot: sensor above item...")
|
||||
await asyncio.sleep(1)
|
||||
await page.screenshot(path=str(SCREENSHOT_DIR / "sensor_above_item.png"))
|
||||
|
||||
# Screenshot 5: Speed sync t=0
|
||||
print("Screenshot: speed sync t0...")
|
||||
await page.screenshot(path=str(SCREENSHOT_DIR / "speed_sync_t0.png"))
|
||||
|
||||
# Screenshot 6: Speed sync t=1 (after 1 second)
|
||||
await asyncio.sleep(1)
|
||||
print("Screenshot: speed sync t1...")
|
||||
await page.screenshot(path=str(SCREENSHOT_DIR / "speed_sync_t1.png"))
|
||||
|
||||
# Wait for routing phase
|
||||
print("Waiting for routing phase...")
|
||||
await asyncio.sleep(5)
|
||||
|
||||
# Screenshot 7: Route to C (need to find a C case)
|
||||
print("Screenshot: route scenarios...")
|
||||
await page.screenshot(path=str(SCREENSHOT_DIR / "route_active.png"))
|
||||
|
||||
# Continue playback to see C/D roll cages
|
||||
await asyncio.sleep(8)
|
||||
await page.screenshot(path=str(SCREENSHOT_DIR / "c_roll_cage.png"))
|
||||
|
||||
await asyncio.sleep(8)
|
||||
await page.screenshot(path=str(SCREENSHOT_DIR / "d_roll_cage.png"))
|
||||
|
||||
# Screenshot 8: No overlay overlap
|
||||
print("Screenshot: overlay no overlap...")
|
||||
await page.screenshot(path=str(SCREENSHOT_DIR / "overlay_no_overlap.png"))
|
||||
|
||||
# Mobile viewport
|
||||
print("Testing mobile viewport...")
|
||||
await context.close()
|
||||
context = await browser.new_context(viewport={"width": 390, "height": 844})
|
||||
page = await context.new_page()
|
||||
|
||||
await page.goto(BASE_URL, wait_until="networkidle", timeout=30000)
|
||||
await asyncio.sleep(2)
|
||||
|
||||
# Start playback on mobile
|
||||
play_button = page.locator(".demo-play-btn, button:has-text('Play'), button:has-text('Запустить')")
|
||||
if await play_button.count() > 0:
|
||||
await play_button.first.click()
|
||||
await asyncio.sleep(3)
|
||||
|
||||
await page.screenshot(path=str(SCREENSHOT_DIR / "mobile_overlay.png"))
|
||||
|
||||
# Check details page
|
||||
print("Checking /details...")
|
||||
await page.goto(f"{BASE_URL}/details", wait_until="networkidle", timeout=30000)
|
||||
await asyncio.sleep(1)
|
||||
await page.screenshot(path=str(SCREENSHOT_DIR / "details_page.png"))
|
||||
|
||||
await context.close()
|
||||
await browser.close()
|
||||
|
||||
# Report
|
||||
print(f"\nScreenshots saved to: {SCREENSHOT_DIR}")
|
||||
if errors:
|
||||
print(f"\nConsole errors found ({len(errors)}):")
|
||||
for e in errors[:10]:
|
||||
print(f" - {e[:100]}")
|
||||
else:
|
||||
print("\nNo console errors found.")
|
||||
|
||||
print("\nQA Complete!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user