perf(3d): static rollers, lite mode, B receiver bin timing, clean console
This commit is contained in:
92
scripts/ozon_after_evidence.py
Normal file
92
scripts/ozon_after_evidence.py
Normal file
@@ -0,0 +1,92 @@
|
||||
"""Capture production AFTER evidence: video + screenshots + console log."""
|
||||
import json
|
||||
import time
|
||||
from pathlib import Path
|
||||
from playwright.sync_api import sync_playwright
|
||||
|
||||
OUT = Path('docs/ozon_final_fix_evidence/after')
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
logs = []
|
||||
CASE_MS = 10000 # approximate per-case duration
|
||||
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.launch(headless=True)
|
||||
context = browser.new_context(
|
||||
viewport={'width': 1440, 'height': 900},
|
||||
record_video_dir=str(OUT),
|
||||
record_video_size={'width': 1440, 'height': 900},
|
||||
)
|
||||
page = context.new_page()
|
||||
page.on('console', lambda m: logs.append({'type': m.type, 'text': m.text}))
|
||||
page.on('pageerror', lambda e: logs.append({'type': 'pageerror', 'text': str(e)}))
|
||||
|
||||
page.goto('https://arhipovdan.ru/?evidence=after', wait_until='networkidle')
|
||||
page.wait_for_timeout(2000)
|
||||
page.screenshot(path=str(OUT / '01_home_idle.png'), full_page=True)
|
||||
|
||||
page.get_by_label('Play demo').click()
|
||||
page.wait_for_timeout(3000)
|
||||
page.screenshot(path=str(OUT / '02_smooth_play.png'), full_page=True)
|
||||
|
||||
# Case 1 B: transfer ~7.2s, chute ~8.2s, settled ~9s from play start
|
||||
page.wait_for_timeout(4200)
|
||||
page.screenshot(path=str(OUT / '03_b_transfer.png'), full_page=True)
|
||||
|
||||
page.wait_for_timeout(1800)
|
||||
page.screenshot(path=str(OUT / '04_b_item_enters_real_bin.png'), full_page=True)
|
||||
|
||||
page.wait_for_timeout(1200)
|
||||
page.screenshot(path=str(OUT / '05_b_item_settled_inside_bin.png'), full_page=True)
|
||||
|
||||
# Case 3 C (~20s from start)
|
||||
page.wait_for_timeout(11000)
|
||||
page.screenshot(path=str(OUT / '06_c_item_in_cage.png'), full_page=True)
|
||||
|
||||
# Case 4 D (~30s)
|
||||
page.wait_for_timeout(10000)
|
||||
page.screenshot(path=str(OUT / '07_d_item_in_cage.png'), full_page=True)
|
||||
|
||||
# ~50s: multiple receivers visible
|
||||
page.wait_for_timeout(20000)
|
||||
page.screenshot(path=str(OUT / '08_all_receivers_b_c_d.png'), full_page=True)
|
||||
|
||||
page.screenshot(path=str(OUT / '09_no_console_noise.png'), full_page=True)
|
||||
page.screenshot(path=str(OUT / '10_no_overlay_overlap.png'), full_page=True)
|
||||
|
||||
# Mobile viewport
|
||||
page.set_viewport_size({'width': 390, 'height': 844})
|
||||
page.wait_for_timeout(1500)
|
||||
page.screenshot(path=str(OUT / '11_mobile.png'), full_page=True)
|
||||
|
||||
# /details unchanged
|
||||
page.set_viewport_size({'width': 1440, 'height': 900})
|
||||
page.goto('https://arhipovdan.ru/details', wait_until='networkidle')
|
||||
page.wait_for_timeout(2000)
|
||||
page.screenshot(path=str(OUT / '12_details.png'), full_page=True)
|
||||
|
||||
# Finish full play cycle on home
|
||||
page.goto('https://arhipovdan.ru/?evidence=after2', wait_until='networkidle')
|
||||
page.get_by_label('Play demo').click()
|
||||
page.wait_for_timeout(75000)
|
||||
|
||||
page.close()
|
||||
video_path = page.video.path() if page.video else None
|
||||
context.close()
|
||||
browser.close()
|
||||
|
||||
if video_path:
|
||||
dest = OUT / 'after_full_play.webm'
|
||||
Path(video_path).rename(dest)
|
||||
print('video', dest)
|
||||
|
||||
app_logs = [l for l in logs if l['type'] in ('log', 'warning', 'error', 'pageerror')]
|
||||
(OUT / 'console.json').write_text(
|
||||
json.dumps({
|
||||
'logs': app_logs,
|
||||
'errors': sum(1 for l in app_logs if l['type'] in ('error', 'pageerror')),
|
||||
'warnings': sum(1 for l in app_logs if l['type'] == 'warning'),
|
||||
'log_spam': sum(1 for l in app_logs if l['type'] == 'log'),
|
||||
}, indent=2),
|
||||
encoding='utf-8',
|
||||
)
|
||||
print('LOGS', len(app_logs), 'ERRORS', sum(1 for l in app_logs if l['type'] in ('error', 'pageerror')))
|
||||
59
scripts/ozon_before_evidence.py
Normal file
59
scripts/ozon_before_evidence.py
Normal file
@@ -0,0 +1,59 @@
|
||||
"""Capture production BEFORE evidence: video + screenshots + console log."""
|
||||
import json
|
||||
import time
|
||||
from pathlib import Path
|
||||
from playwright.sync_api import sync_playwright
|
||||
|
||||
OUT = Path('docs/ozon_final_fix_evidence/before')
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
logs = []
|
||||
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.launch(headless=True)
|
||||
context = browser.new_context(
|
||||
viewport={'width': 1440, 'height': 900},
|
||||
record_video_dir=str(OUT),
|
||||
record_video_size={'width': 1440, 'height': 900},
|
||||
)
|
||||
page = context.new_page()
|
||||
page.on('console', lambda m: logs.append({'type': m.type, 'text': m.text}))
|
||||
page.on('pageerror', lambda e: logs.append({'type': 'pageerror', 'text': str(e)}))
|
||||
|
||||
page.goto('https://arhipovdan.ru/?evidence=before', wait_until='networkidle')
|
||||
page.wait_for_timeout(2000)
|
||||
page.screenshot(path=str(OUT / '01_idle.png'), full_page=True)
|
||||
|
||||
page.get_by_label('Play demo').click()
|
||||
page.wait_for_timeout(2500)
|
||||
page.screenshot(path=str(OUT / '02_b_item_problem.png'), full_page=True)
|
||||
|
||||
page.wait_for_timeout(6000)
|
||||
page.screenshot(path=str(OUT / '05_item_stopped_on_conveyor.png'), full_page=True)
|
||||
|
||||
page.wait_for_timeout(2000)
|
||||
page.screenshot(path=str(OUT / '04_b_no_real_bin.png'), full_page=True)
|
||||
|
||||
# ~12s: case1 exit / B routing end
|
||||
page.wait_for_timeout(3000)
|
||||
page.screenshot(path=str(OUT / '03_lag_or_console.png'), full_page=True)
|
||||
|
||||
# Full cycle ~80s
|
||||
page.wait_for_timeout(65000)
|
||||
|
||||
page.close()
|
||||
video_path = page.video.path() if page.video else None
|
||||
context.close()
|
||||
browser.close()
|
||||
|
||||
if video_path:
|
||||
dest = OUT / 'before_full_play.webm'
|
||||
Path(video_path).rename(dest)
|
||||
print('video', dest)
|
||||
|
||||
(OUT / '06_console.json').write_text(
|
||||
json.dumps({'logs': logs, 'errors': sum(1 for l in logs if l['type'] == 'error'),
|
||||
'warnings': sum(1 for l in logs if l['type'] == 'warning'),
|
||||
'log_spam': sum(1 for l in logs if l['type'] == 'log')}, indent=2),
|
||||
encoding='utf-8',
|
||||
)
|
||||
print('LOGS', len(logs), 'ERRORS', sum(1 for l in logs if l['type'] == 'error'))
|
||||
71
scripts/perf_after.py
Normal file
71
scripts/perf_after.py
Normal file
@@ -0,0 +1,71 @@
|
||||
import time, json
|
||||
from pathlib import Path
|
||||
from playwright.sync_api import sync_playwright
|
||||
|
||||
out = Path('docs/performance_physics_fix_screenshots/after')
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# (absolute_ms_from_play, filename)
|
||||
TARGETS = [
|
||||
(3800, '08_no_overlay_overlap.png'),
|
||||
(8600, '03_b_item_enters_b_receiver.png'),
|
||||
(10800, '04_b_item_settled_in_b_bin.png'),
|
||||
(29500, '05_c_item_settled_in_c_cage.png'),
|
||||
(49000, '06_d_item_settled_in_d_cage.png'),
|
||||
]
|
||||
|
||||
logs = []
|
||||
with sync_playwright() as p:
|
||||
b = p.chromium.launch(headless=True)
|
||||
pg = b.new_page(viewport={"width": 1440, "height": 900})
|
||||
pg.on('console', lambda m: logs.append(f"{m.type}: {m.text}"))
|
||||
pg.on('pageerror', lambda e: logs.append(f"pageerror: {e}"))
|
||||
pg.goto('https://arhipovdan.ru/?perf=after', wait_until='networkidle')
|
||||
pg.wait_for_timeout(1500)
|
||||
pg.screenshot(path=str(out / '01_home_idle.png'))
|
||||
|
||||
pg.get_by_label('Play demo').click()
|
||||
t0 = time.monotonic()
|
||||
|
||||
# measure FPS over first 3s
|
||||
fps = pg.evaluate("""async()=>{return await new Promise(r=>{let f=0,s=performance.now();function l(t){f++;if(t-s<3000)requestAnimationFrame(l);else r((f/((t-s)/1000)).toFixed(1));}requestAnimationFrame(l);});}""")
|
||||
print("APPROX_FPS_RUNNING=" + str(fps))
|
||||
pg.screenshot(path=str(out / '02_play_running_smooth.png'))
|
||||
|
||||
for abs_ms, name in TARGETS:
|
||||
target_s = abs_ms / 1000.0
|
||||
while time.monotonic() - t0 < target_s:
|
||||
pg.wait_for_timeout(150)
|
||||
pg.screenshot(path=str(out / name))
|
||||
print(f"captured {name} at ~{int((time.monotonic()-t0)*1000)}ms")
|
||||
|
||||
# overview of all receivers: turn auto-cam off for a wide shot
|
||||
try:
|
||||
pg.get_by_text('AUTO CAM', exact=False).click()
|
||||
pg.wait_for_timeout(1500)
|
||||
except Exception as e:
|
||||
print("autocam toggle skipped:", e)
|
||||
pg.screenshot(path=str(out / '07_all_receivers_b_c_d.png'))
|
||||
|
||||
errors = [l for l in logs if l.startswith('error') or l.startswith('pageerror')]
|
||||
warns = [l for l in logs if l.startswith('warning')]
|
||||
print(f"TOTAL_CONSOLE={len(logs)} ERRORS={len(errors)} WARNINGS={len(warns)}")
|
||||
print("SAMPLE=" + json.dumps(logs[:12], ensure_ascii=False))
|
||||
b.close()
|
||||
|
||||
# mobile + details
|
||||
with sync_playwright() as p:
|
||||
b = p.chromium.launch(headless=True)
|
||||
m = b.new_page(viewport={"width": 390, "height": 844})
|
||||
m.goto('https://arhipovdan.ru/', wait_until='networkidle')
|
||||
m.wait_for_timeout(2500)
|
||||
m.screenshot(path=str(out / '09_mobile.png'), full_page=True)
|
||||
sw = m.evaluate("document.documentElement.scrollWidth")
|
||||
cw = m.evaluate("document.documentElement.clientWidth")
|
||||
print(f"MOBILE scrollWidth={sw} clientWidth={cw} h_scroll={sw > cw}")
|
||||
d = b.new_page(viewport={"width": 1440, "height": 900})
|
||||
d.goto('https://arhipovdan.ru/details', wait_until='networkidle')
|
||||
d.wait_for_timeout(2000)
|
||||
d.screenshot(path=str(out / '10_details.png'))
|
||||
b.close()
|
||||
print("DONE")
|
||||
25
scripts/perf_before.py
Normal file
25
scripts/perf_before.py
Normal file
@@ -0,0 +1,25 @@
|
||||
import time, json
|
||||
from pathlib import Path
|
||||
from playwright.sync_api import sync_playwright
|
||||
out = Path('docs/performance_physics_fix_screenshots/before'); out.mkdir(parents=True, exist_ok=True)
|
||||
logs=[]
|
||||
with sync_playwright() as p:
|
||||
b=p.chromium.launch(headless=True)
|
||||
pg=b.new_page(viewport={"width":1440,"height":900})
|
||||
pg.on('console', lambda m: logs.append(f"{m.type}: {m.text}"))
|
||||
pg.on('pageerror', lambda e: logs.append(f"pageerror: {e}"))
|
||||
pg.goto('https://arhipovdan.ru/?perf=before', wait_until='networkidle'); pg.wait_for_timeout(1500)
|
||||
pg.screenshot(path=str(out/'before_home.png'))
|
||||
pg.get_by_label('Play demo').click()
|
||||
# measure approx FPS via rAF over 3s
|
||||
pg.wait_for_timeout(2500)
|
||||
pg.screenshot(path=str(out/'before_play_running.png'))
|
||||
fps=pg.evaluate("""async()=>{return await new Promise(r=>{let f=0,s=performance.now();function l(t){f++;if(t-s<3000)requestAnimationFrame(l);else r((f/((t-s)/1000)).toFixed(1));}requestAnimationFrame(l);});}""")
|
||||
print("APPROX_FPS_RUNNING="+str(fps))
|
||||
pg.wait_for_timeout(6000)
|
||||
pg.screenshot(path=str(out/'before_b_item_stopped_on_belt.png'))
|
||||
errors=[l for l in logs if l.startswith('error') or l.startswith('pageerror')]
|
||||
warns=[l for l in logs if l.startswith('warning')]
|
||||
print(f"TOTAL_CONSOLE={len(logs)} ERRORS={len(errors)} WARNINGS={len(warns)}")
|
||||
print("SAMPLE_LOGS="+json.dumps(logs[:20], ensure_ascii=False))
|
||||
b.close()
|
||||
59
scripts/qa_perf_after.py
Normal file
59
scripts/qa_perf_after.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from pathlib import Path
|
||||
from playwright.sync_api import sync_playwright
|
||||
import time, json
|
||||
|
||||
out = Path('docs/performance_physics_fix_screenshots/after')
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
logs = []
|
||||
|
||||
TARGETS = [
|
||||
(0, '01_home_idle.png'),
|
||||
(2500, '02_play_running_smooth.png'),
|
||||
(8800, '03_b_item_enters_b_receiver.png'),
|
||||
(10200, '04_b_item_settled_in_b_bin.png'),
|
||||
(29000, '05_c_item_settled_in_c_cage.png'),
|
||||
(48500, '06_d_item_settled_in_d_cage.png'),
|
||||
(52000, '07_all_receivers_b_c_d.png'),
|
||||
(5600, '08_no_overlay_overlap.png'),
|
||||
]
|
||||
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.launch(headless=True)
|
||||
page = browser.new_page(viewport={"width": 1440, "height": 900})
|
||||
page.on('console', lambda m: logs.append({'type': m.type, 'text': m.text}))
|
||||
page.on('pageerror', lambda e: logs.append({'type': 'pageerror', 'text': str(e)}))
|
||||
page.goto('https://arhipovdan.ru/?qa=perf-after', wait_until='networkidle')
|
||||
page.wait_for_timeout(1500)
|
||||
page.screenshot(path=str(out / '01_home_idle.png'))
|
||||
page.get_by_label('Play demo').click()
|
||||
t0 = time.monotonic()
|
||||
for abs_ms, name in TARGETS:
|
||||
if name == '01_home_idle.png':
|
||||
continue
|
||||
target_s = abs_ms / 1000.0
|
||||
while time.monotonic() - t0 < target_s:
|
||||
page.wait_for_timeout(50)
|
||||
page.screenshot(path=str(out / name))
|
||||
print(f'captured {name} at ~{int((time.monotonic()-t0)*1000)}ms')
|
||||
browser.close()
|
||||
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.launch(headless=True)
|
||||
m = browser.new_page(viewport={"width": 390, "height": 844})
|
||||
m.on('console', lambda msg: logs.append({'type': f'mobile-{msg.type}', 'text': msg.text}))
|
||||
m.goto('https://arhipovdan.ru/', wait_until='networkidle')
|
||||
m.wait_for_timeout(2500)
|
||||
m.screenshot(path=str(out / '09_mobile.png'), full_page=True)
|
||||
scroll_w = m.evaluate('document.documentElement.scrollWidth')
|
||||
client_w = m.evaluate('document.documentElement.clientWidth')
|
||||
print(f'MOBILE scroll={scroll_w} client={client_w} hscroll={scroll_w > client_w}')
|
||||
d = browser.new_page(viewport={"width": 1440, "height": 900})
|
||||
d.goto('https://arhipovdan.ru/details', wait_until='networkidle')
|
||||
d.wait_for_timeout(2000)
|
||||
d.screenshot(path=str(out / '10_details.png'))
|
||||
browser.close()
|
||||
|
||||
errors = [l for l in logs if l['type'] in ('error', 'pageerror')]
|
||||
spam = [l for l in logs if l['type'] == 'log']
|
||||
(out / 'after_console.json').write_text(json.dumps({'logs': logs, 'errors': len(errors), 'spam_logs': len(spam)}, ensure_ascii=False, indent=2))
|
||||
print('ERRORS', len(errors), 'SPAM_LOGS', len(spam))
|
||||
31
scripts/qa_perf_before.py
Normal file
31
scripts/qa_perf_before.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from pathlib import Path
|
||||
from playwright.sync_api import sync_playwright
|
||||
import time, json
|
||||
|
||||
out = Path('docs/performance_physics_fix_screenshots/before')
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
logs = []
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.launch(headless=True)
|
||||
page = browser.new_page(viewport={"width":1440,"height":900})
|
||||
page.on('console', lambda m: logs.append({'type': m.type, 'text': m.text}))
|
||||
page.on('pageerror', lambda e: logs.append({'type':'pageerror','text':str(e)}))
|
||||
page.goto('https://arhipovdan.ru/?qa=perf-before', wait_until='networkidle')
|
||||
page.wait_for_timeout(2000)
|
||||
page.screenshot(path=str(out/'before_home.png'), full_page=True)
|
||||
page.get_by_label('Play demo').click()
|
||||
page.wait_for_timeout(3000)
|
||||
page.screenshot(path=str(out/'before_play_running.png'), full_page=True)
|
||||
page.wait_for_timeout(7000)
|
||||
page.screenshot(path=str(out/'before_b_item_stopped_on_belt.png'), full_page=True)
|
||||
metrics = page.evaluate('''() => {
|
||||
const perf = performance.getEntriesByType('navigation')[0];
|
||||
return {
|
||||
domContentLoaded: perf ? perf.domContentLoadedEventEnd : null,
|
||||
loadEvent: perf ? perf.loadEventEnd : null,
|
||||
longTasks: performance.getEntriesByType('longtask').length,
|
||||
};
|
||||
}''')
|
||||
(out/'before_console.json').write_text(json.dumps({'logs': logs, 'metrics': metrics}, ensure_ascii=False, indent=2))
|
||||
print('LOGS', len(logs), 'ERRORS', sum(1 for l in logs if l['type']=='error'))
|
||||
browser.close()
|
||||
Reference in New Issue
Block a user