evalflow-ci-lab / test_browser.py
Hugdrigo's picture
Upload 44 files
2e85669 verified
Raw History Blame Contribute Delete
6.59 kB
import asyncio, pathlib, json
from playwright.async_api import async_playwright
ROOT=pathlib.Path(__file__).resolve().parent
OUT=pathlib.Path('/mnt/data')
async def main():
async with async_playwright() as p:
browser=await p.chromium.launch(headless=True,executable_path='/usr/bin/chromium',args=['--no-sandbox'])
page=await browser.new_page(viewport={'width':1512,'height':1020},accept_downloads=True)
errs=[];page.on('pageerror',lambda e:errs.append(str(e)))
await page.set_content((ROOT/'index.html').read_text(),wait_until='domcontentloaded')
await page.add_style_tag(content=(ROOT/'styles.css').read_text())
blob=(ROOT/'robustness_snapshots.json').read_text()
await page.evaluate('''(blob)=>{window.fetch=async (uri)=>String(uri).endsWith('robustness_snapshots.json')?{ok:true,json:async()=>JSON.parse(blob)}:{ok:false,status:404};}''',blob)
await page.add_script_tag(content=(ROOT/'evalflow_engine.js').read_text())
await page.add_script_tag(content=(ROOT/'app.js').read_text())
await page.wait_for_function("document.querySelector('#dataStatus').textContent==='SNAPSHOT LOADED'",timeout=40000)
checks=[]
async def ck(name,expr):
if not expr:raise AssertionError(name+'; browser errors='+repr(errs))
checks.append(name);print('PASS',name)
await ck('hero displays EvalFlow','EvalFlow' in await page.locator('h1').inner_text())
await ck('source 4416 records','4,416' in await page.locator('#heroRecords').inner_text())
await ck('nine research views',await page.locator('.nav-btn').count()==9)
await ck('default decision PASS','PASS' in await page.locator('#content').inner_text())
await ck('default hybrid accuracy 77.8%', '77.8%' in await page.locator('#content').inner_text())
await ck('default run registry starts with one', await page.locator('#dataStatus').inner_text()=='SNAPSHOT LOADED')
await page.locator('#baseline').select_option('hybrid')
await page.locator('#candidate').select_option('nb')
await page.locator('#run').click()
await ck('regression candidate BLOCK','BLOCK' in await page.locator('#content').inner_text())
await page.locator('#baseline').select_option('nb')
await page.locator('#candidate').select_option('hybrid')
await page.locator('#run').click()
await ck('recovery to passing candidate','ALL GATES PASS' in await page.locator('#content').inner_text())
await page.locator('[data-view=pipeline]').click()
await ck('seven pipeline stages',await page.locator('.step').count()==7)
await ck('CLI displayed','node ci_evalflow.js' in await page.locator('#content').inner_text())
await page.locator('[data-view=regressions]').click()
await ck('regression audit cases displayed',await page.locator('.case').count()>0)
await page.locator('#caseFilter').select_option('improved')
await ck('improvement filter works',await page.locator('.case').count()>0)
await page.locator('#caseSearch').fill('ari-')
await ck('case search works',await page.locator('.case').count()>0)
await page.locator('[data-view=gates]').click()
await ck('gate policy editor 8 fields',await page.locator('input[id^=policy_]').count()==8)
await page.locator('#policy_minAccuracy').fill('0.95')
await page.locator('#applyPolicy').click()
await ck('strict gate policy blocks','BLOCK' in await page.locator('#content').inner_text())
await page.locator('#resetPolicy').click()
await ck('reset gate policy passes','PASS' in await page.locator('#content').inner_text())
await page.locator('[data-view=slices]').click()
await ck('slices show 3 languages','Português' not in await page.locator('#content').inner_text() or await page.locator('table tbody tr').count()==3)
await page.locator('#sliceKey').select_option('domain')
await ck('single mixed-domain challenge warning', 'domain-to-domain comparisons' in await page.locator('#content').inner_text())
await page.locator('[data-view=stress]').click()
await ck('six stress test conditions',await page.locator('table tbody tr').count()==6)
await ck('destructive edit unscored','Not scored' in await page.locator('#content').inner_text())
await page.locator('[data-view=registry]').click()
await ck('run registry accessible',await page.locator('table tbody tr').count()>=3)
await page.locator('[data-view=automation]').click()
await ck('real CI commands shown','node test_engine.js' in await page.locator('#content').inner_text())
await ck('optional GitHub workflow warning','not enabled' in (await page.locator('#content').inner_text()).lower())
await page.locator('[data-view=export]').click()
for kind,ext in [('report','.md'),('result','.json'),('paired','.csv'),('gates','.csv'),('registry','.json')]:
async with page.expect_download() as d:await page.locator(f'[data-export={kind}]').click()
item=await d.value
await ck('export '+kind,item.suggested_filename.endswith(ext))
original=json.loads(blob)
small={'rows':[r for r in original['rows'] if not (r['method']=='hybrid' and r['split']=='challenge' and r['attack']=='typo' and r['id']==original['rows'][-1]['id'])]}
await page.locator('#importJson').set_input_files({'name':'research_import.json','mimeType':'application/json','buffer':json.dumps(small).encode()})
await page.wait_for_function("document.querySelector('#dataStatus').textContent.includes('LOCAL IMPORT')")
await ck('import custom JSON locally',await page.locator('#dataStatus').inner_text()=='LOCAL IMPORT · UNVERIFIED SOURCE')
await page.locator('#restore').click()
await page.wait_for_function("document.querySelector('#dataStatus').textContent==='SNAPSHOT LOADED'")
await ck('restore bundled evidence',await page.locator('#dataStatus').inner_text()=='SNAPSHOT LOADED')
await page.locator('[data-view=overview]').click()
await page.evaluate('window.scrollTo(0,0)')
await page.wait_for_timeout(150)
await page.screenshot(path=str(OUT/'EvalFlow_CI_Lab_DESKTOP_PREVIEW.png'),full_page=True)
await ck('desktop no sideways scroll',await page.evaluate('document.documentElement.scrollWidth <= window.innerWidth+3'))
await page.set_viewport_size({'width':390,'height':844})
await page.evaluate('scrollTo(0,0)')
await page.screenshot(path=str(OUT/'EvalFlow_CI_Lab_MOBILE_PREVIEW.png'),full_page=True)
await ck('mobile no sideways scroll',await page.evaluate('document.documentElement.scrollWidth <= window.innerWidth+3'))
await ck('mobile navigation accessible',await page.locator('[data-view=export]').is_visible())
await ck('no browser JavaScript errors',len(errs)==0)
print('TOTAL BROWSER CHECKS',len(checks),'PASS')
await browser.close()
asyncio.run(main())