import asyncio, pathlib, json from playwright.async_api import async_playwright ROOT=pathlib.Path(__file__).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':1000},accept_downloads=True) errors=[];page.on('pageerror',lambda e:errors.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()) for fn in ('source_modelops_engine.js','robustness_engine.js'): await page.add_script_tag(content=(ROOT/fn).read_text()) blobs={n:(ROOT/n).read_text() for n in ('robustness_snapshots.json','benchmark_manifest.json','train.json')} await page.evaluate('''(blobs)=>{const old=window.fetch;window.fetch=async (url)=>{if(Object.prototype.hasOwnProperty.call(blobs,String(url)))return {ok:true,json:async()=>JSON.parse(blobs[String(url)])};return old(url);}}''',blobs) await page.add_script_tag(content=(ROOT/'app.js').read_text()) await page.wait_for_function("document.querySelector('#status').textContent==='SNAPSHOT VERIFIED'",timeout=30000) checks=[] async def ck(name,condition): if not condition:raise AssertionError(name+' | browser errors: '+repr(errors)) checks.append(name);print('PASS',name) await ck('hero displays robustness studio','Robustness' in await page.locator('h1').inner_text()) await ck('4416 records loaded', '4,416' in await page.locator('#snapN').inner_text()) await ck('eight navigation modules',await page.locator('.nav-btn').count()==8) await ck('overview original hybrid baseline 77.8%', '77.8%' in await page.locator('#panel').inner_text()) await ck('change coverage display', '54 total' in await page.locator('#panel').inner_text()) await page.locator('#methodSelect').select_option('nb') await ck('NB method changes score', '74.1%' in await page.locator('#panel').inner_text()) await page.locator('#splitSelect').select_option('iid') await ck('IID split shows 130 rows', '130 total' in await page.locator('#panel').inner_text()) await page.locator('#attackSelect').select_option('truncate') await ck('destructive edit never scored', 'Not scored' in await page.locator('#panel').inner_text()) await page.locator('#attackSelect').select_option('synonym') await ck('sparse synonym changes show matched coverage', 'Changed inputs' in await page.locator('#panel').inner_text()) await page.locator('#splitSelect').select_option('challenge') await page.locator('#attackSelect').select_option('context') await page.locator('[data-view=matrix]').click() await ck('stress matrix renders six test conditions', await page.locator('#panel tbody tr').first.count()==1 and 'Information removal' in await page.locator('#panel').inner_text()) await ck('all model comparisons render', 'Character TF-IDF' in await page.locator('#panel').inner_text()) await page.locator('[data-view=cases]').click() await ck('paired example view', 'Evidence trail' in await page.locator('#panel').inner_text()) await page.locator('#caseFilter').select_option('flips') await ck('flip filter matches changed predictions', await page.locator('.case').count()>0 and await page.locator('.case').count()<=12) await page.locator('#caseSearch').fill('ari-') await ck('paired search is usable',await page.locator('.case').count()>0) await page.locator('[data-view=selective]').click() await ck('risk curve renders',await page.locator('.svg-chart').count()==1) await page.locator('#coverageRange').fill('50') await ck('coverage slider changes sample count', '50%' in await page.locator('#panel').inner_text()) await page.locator('[data-view=reliability]').click() await ck('NB confidence reliability bins render',await page.locator('#panel tbody tr').count()==8) await ck('uncalibrated warning displayed', 'uncalibrated' in (await page.locator('#panel').inner_text()).lower()) await page.locator('[data-view=slices]').click() await page.locator('#sliceBy').select_option('domain') await ck('domain slice filter', 'Research domain' in await page.locator('#panel').inner_text() or 'Subgroup' in await page.locator('#panel').inner_text()) await page.locator('[data-view=gates]').click() await ck('gate dashboard visible', 'Research gates' in await page.locator('#viewId').inner_text() or 'RESEARCH GATES' in await page.locator('#viewId').inner_text()) await page.locator('#gateFlip').fill('100') await page.locator('#gateDrop').fill('100') await page.locator('#gateMin').fill('1') await page.locator('#applyGates').click() await ck('relaxed gates pass', 'CHECKS PASS' in await page.locator('#panel').inner_text()) await page.locator('#resetGates').click() await ck('gate reset restores strict thresholds','15%' in await page.locator('#panel').inner_text()) await page.locator('[data-view=sandbox]').click() await ck('sandbox has input text',await page.locator('#sandboxText').count()==1) await page.locator('#sandboxLang').select_option('es') await page.locator('#sandboxExample').click() await ck('Spanish example button', 'Los resultados' in await page.locator('#sandboxText').input_value()) await page.locator('#sandboxRun').click() await ck('local prediction creates trace', 'TRANSFORMED' in await page.locator('#panel').inner_text()) for kind,extension in [('report','.md'),('table','.csv'),('session','.json'),('predictions','.csv')]: async with page.expect_download() as info: await page.locator(f'[data-export="{kind}"]').click() download=await info.value await ck('download '+kind,download.suggested_filename.endswith(extension)) async with page.expect_download() as info: await page.locator('#exportSummary').click() dl=await info.value await ck('global research report download', dl.suggested_filename.endswith('.md')) await page.locator('[data-view=overview]').click() await page.locator('#methodSelect').select_option('hybrid') await page.locator('#splitSelect').select_option('challenge') await page.locator('#attackSelect').select_option('typo') await page.evaluate('window.scrollTo(0,0)') await page.screenshot(path=str(OUT/'RobustnessLab_AI_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('window.scrollTo(0,0)') await page.screenshot(path=str(OUT/'RobustnessLab_AI_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=matrix]').is_visible()) await ck('no browser JavaScript errors',not errors) print('TOTAL BROWSER CHECKS',len(checks),'PASS') await browser.close() asyncio.run(main())