Spaces:
Running
Running
Download test_browser.py from Hugdrigo/modelguard-observatory: direct link, hf CLI and curl.
- Browser
- Download file 7.62 kB
-
https://huggingface.co/spaces/Hugdrigo/modelguard-observatory/resolve/main/test_browser.py
- Command line
-
hf download hf://spaces/Hugdrigo/modelguard-observatory/test_browser.py
-
curl -L -o test_browser.py https://huggingface.co/spaces/Hugdrigo/modelguard-observatory/resolve/main/test_browser.py
7.62 kB
| import asyncio, json, pathlib, csv | |
| from playwright.async_api import async_playwright | |
| ROOT=pathlib.Path(__file__).parent | |
| 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':1060},accept_downloads=True) | |
| errors=[] | |
| page.on('pageerror', lambda exc: errors.append(str(exc))) | |
| source=(ROOT/'index.html').read_text() | |
| # Set content, then add source scripts, intercept JSON responses using a fetch shim. | |
| await page.set_content(source, wait_until='domcontentloaded') | |
| await page.add_style_tag(content=(ROOT/'styles.css').read_text()) | |
| for script in (ROOT/'engine.js',): await page.add_script_tag(content=script.read_text()) | |
| source_json=(ROOT/'evaluation_snapshots.json').read_text() | |
| manifest=(ROOT/'benchmark_manifest.json').read_text() | |
| await page.evaluate('''({data,manifest}) => { const f = window.fetch; window.fetch = async (url) => { | |
| if(String(url).includes('evaluation_snapshots.json')) return {ok:true,json:async()=>JSON.parse(data)}; | |
| if(String(url).includes('benchmark_manifest.json')) return {ok:true,json:async()=>JSON.parse(manifest)}; | |
| return f(url); | |
| }}''',{'data':source_json,'manifest':manifest}) | |
| await page.add_script_tag(content=(ROOT/'app.js').read_text()) | |
| await page.locator('.metric').first.wait_for(timeout=10000) | |
| checks=[] | |
| async def ck(label,cond): | |
| if not cond: raise AssertionError(label) | |
| checks.append(label) | |
| print('PASS',label) | |
| await ck('initial overview page', await page.locator('h2').first.inner_text()=='Evaluation overview') | |
| await ck('736 prediction records', '736' in await page.locator('#heroN').inner_text()) | |
| await ck('initial gate warning visible', 'release check' in (await page.locator('#panel').inner_text()).lower()) | |
| await ck('hybrid initial metrics 77.8', '77.8%' in await page.locator('#panel').inner_text()) | |
| await page.locator('#methodSelect').select_option('nb') | |
| await ck('model selector updates to naive bayes', '74.1%' in await page.locator('#panel').inner_text()) | |
| await page.locator('#splitSelect').select_option('iid') | |
| await ck('split selector 100 percent baseline', '100.0%' in await page.locator('#panel').inner_text()) | |
| await page.locator('[data-view="drift"]').click() | |
| await ck('drift section shows PSI and JSD', 'Text-length PSI' in await page.locator('#panel').inner_text() and 'Language JSD' in await page.locator('#panel').inner_text()) | |
| await page.locator('[data-view="slices"]').click() | |
| await ck('slice view has language controls', await page.locator('#sliceBy').count()==1) | |
| await page.locator('#sliceBy').select_option('truth') | |
| await ck('slice view label option', 'Six rhetorical classes' not in await page.locator('#panel').inner_text() and 'background' in await page.locator('#panel').inner_text()) | |
| await page.locator('[data-view="errors"]').click() | |
| await ck('confusion matrix visible', 'CONFUSION MATRIX' in await page.locator('#panel').inner_text()) | |
| await page.locator('#splitSelect').select_option('challenge') | |
| await ck('challenge examples show errors', await page.locator('span.tag.bad').count()>0) | |
| await page.locator('#errorBy').select_option('limitation') | |
| await ck('error filter changes view', 'Misclassifications' in await page.locator('#panel').inner_text()) | |
| await page.locator('[data-view="regression"]').click() | |
| await ck('paired model compare n54', 'Matched example IDs' in await page.locator('#panel').inner_text()) | |
| await page.locator('#compareMethod').select_option('word') | |
| await ck('paired method updates', 'Word TF-IDF' in await page.locator('#panel').inner_text()) | |
| await page.locator('[data-view="gates"]').click() | |
| await ck('default release gates fail', 'CONFIGURED CHECKS FAIL' in await page.locator('#panel').inner_text()) | |
| await page.locator('#tPSI').fill('1.0') | |
| await page.locator('#tGap').fill('30') | |
| await page.locator('#tAccuracy').fill('70') | |
| await page.locator('#applyGates').click() | |
| await ck('thresholds change gate view without modifying data', 'CONFIGURED CHECKS PASS' in await page.locator('#panel').inner_text()) | |
| await page.locator('#resetGates').click() | |
| await ck('reset restores research defaults', 'CONFIGURED CHECKS FAIL' in await page.locator('#panel').inner_text()) | |
| await page.locator('[data-view="registry"]').click() | |
| await ck('registry lists SHA256', 'evaluationSha256' in await page.locator('#panel').inner_text()) | |
| await ck('registry shows lineage', 'Academic Rhetorical Intent Mini' in await page.locator('#panel').inner_text()) | |
| await page.locator('[data-view="export"]').click() | |
| async with page.expect_download() as d: | |
| await page.locator('[data-download="rows"]').click() | |
| dl=await d.value | |
| await ck('CSV export generated',dl.suggested_filename.endswith('.csv')) | |
| async with page.expect_download() as d: | |
| await page.locator('[data-download="session"]').click() | |
| dl=await d.value | |
| await ck('full JSON session downloaded',dl.suggested_filename.endswith('.json')) | |
| async with page.expect_download() as d: | |
| await page.locator('[data-download="report"]').click() | |
| dl=await d.value | |
| await ck('Markdown audit report downloaded',dl.suggested_filename.endswith('.md')) | |
| async with page.expect_download() as d: | |
| await page.locator('[data-download="template"]').click() | |
| dl=await d.value | |
| await ck('CSV import template downloaded', 'template' in dl.suggested_filename) | |
| await page.locator('#inputFile').set_input_files(files={'name':'custom.json','mimeType':'application/json','buffer':json.dumps({'rows':[dict(id='custom1',split='challenge',method='nb',language='en',domain='test',truth='background',pred='background',tokenCount=4)]}).encode()}) | |
| await page.locator('#importBtn').click() | |
| await page.wait_for_timeout(150);await ck('user import applied', '1' in await page.locator('#heroN').inner_text() and 'Imported 1 rows' in await page.locator('#notice').inner_text()) | |
| await page.locator('[data-view="export"]').click() | |
| await page.locator('#restoreBtn').click() | |
| await ck('restores original dataset', '736' in await page.locator('#heroN').inner_text()) | |
| await page.locator('#methodSelect').select_option('hybrid') | |
| await page.locator('#notice').evaluate('(el)=>el.hidden=true') | |
| await page.set_viewport_size({'width':390,'height':844}) | |
| await page.screenshot(path='/mnt/data/ModelGuard_Observatory_MOBILE_PREVIEW.png',full_page=True) | |
| await ck('mobile viewport does not overflow', await page.evaluate('document.documentElement.scrollWidth <= window.innerWidth + 3')) | |
| await ck('navigation persists on mobile', await page.locator('[data-view="drift"]').is_visible()) | |
| await page.set_viewport_size({'width':1512,'height':1050}) | |
| await page.locator('[data-view="overview"]').click() | |
| await page.screenshot(path='/mnt/data/ModelGuard_Observatory_DESKTOP_PREVIEW.png',full_page=True) | |
| await ck('no browser JavaScript errors', not errors) | |
| print('BROWSER TESTS',len(checks),'PASS') | |
| await browser.close() | |
| asyncio.run(main()) | |