"""Browser regression for the paper Atlas refresh; uses real full-corpus lookup. Run against the built server with a pinned Atlas release. Set CHROMIUM_PATH and PREVIEW_URL for local installations. No live inference jobs are submitted. """ import json import os from pathlib import Path from playwright.sync_api import sync_playwright, expect ROOT = Path(__file__).resolve().parents[1] OUT = ROOT/'artifacts/atlas-refresh-20261110' BASE = os.environ.get('PREVIEW_URL','http://127.0.0.1:7860') CASES = json.loads((ROOT/'public/data/atlas-cases.json').read_text()) POINTS = json.loads((ROOT/'public/data/atlas-map.json').read_text()) checks=[] def passed(message): checks.append(message) print(message,flush=True) with sync_playwright() as p: browser=p.chromium.launch(executable_path=os.environ.get('CHROMIUM_PATH'),args=['--no-sandbox','--disable-dev-shm-usage','--use-gl=angle','--use-angle=swiftshader','--enable-unsafe-swiftshader']) context=browser.new_context(viewport={'width':1440,'height':1050},device_scale_factor=1) page=context.new_page();errors=[];requests=[] page.on('pageerror',lambda e:errors.append(str(e))) page.on('request',lambda r:requests.append(r.url)) page.goto(BASE+'/atlas',wait_until='domcontentloaded') expect(page.locator('.atlas-marker')).to_have_count(8) assert page.locator('.atlas-map-error').count()==0 expect(page.locator('.atlas-case')).to_have_count(8) boxes=page.locator('.atlas-marker').evaluate_all('(els)=>els.map(e=>{let r=e.getBoundingClientRect();return {x:r.x,y:r.y,w:r.width,h:r.height}})') for i,a in enumerate(boxes): for b in boxes[i+1:]: assert a['x']+a['w']<=b['x'] or b['x']+b['w']<=a['x'] or a['y']+a['h']<=b['y'] or b['y']+b['h']<=a['y'], 'Overlapping case markers' page.wait_for_timeout(750) page.screenshot(path=str(OUT/'final-atlas.png'),full_page=True) passed('Eight separated paper landmarks render on the real WebGL map') for i,c in enumerate(CASES): page.locator('.atlas-case').nth(i).click() expect(page.locator('.atlas-detail-body h2')).to_have_text(c['uniref_id']) page.locator('.atlas-structure .molecule[data-render-state="ready"]').wait_for(timeout=30000) expect(page.locator('.atlas-marker.selected')).to_have_count(1) passed('All eight case cards, structures and selected map locations work') page.get_by_role('button',name='Next showcase',exact=True).click() expect(page.locator('.atlas-detail-body h2')).to_have_text(CASES[0]['uniref_id']) page.reload(wait_until='domcontentloaded') expect(page.locator('.atlas-detail-body h2')).to_have_text(CASES[0]['uniref_id']) page.get_by_role('button',name='Next showcase',exact=True).click();page.go_back() expect(page.locator('.atlas-detail-body h2')).to_have_text(CASES[0]['uniref_id']) passed('Case next/previous navigation, deep links, refresh and browser history preserve selection') page.get_by_role('button',name='pLDDT confidence',exact=True).click() expect(page.get_by_role('button',name='pLDDT confidence',exact=True)).to_have_attribute('aria-pressed','true') page.get_by_role('button',name='N → C terminus',exact=True).click() page.get_by_role('button',name='Swiss-Prot overlap',exact=True).click() expect(page.get_by_role('button',name='Swiss-Prot overlap',exact=True)).to_have_attribute('aria-pressed','true') page.get_by_role('button',name='Sequence communities',exact=True).click() page.get_by_role('button',name='Reset map',exact=True).click() expect(page.locator('.atlas-marker')).to_have_count(8) page.get_by_role('button',name='Zoom in',exact=True).click();page.get_by_role('button',name='Zoom out',exact=True).click() canvas=page.locator('.atlas-map canvas');canvas.focus();page.keyboard.press('ArrowLeft');page.keyboard.press('0') page.wait_for_timeout(600);page.locator('.atlas-workspace').screenshot(path=str(OUT/'final-atlas-selected.png')) passed('Coverage layer, structure coloring, zoom/reset and keyboard pan work') outside='UniRef50_A0A418SD25';assert outside not in POINTS['ids'] field=page.get_by_role('textbox',name='Find an Atlas record by ID') field.fill(outside[9:].lower());page.get_by_role('button',name='Find protein',exact=False).click() expect(page.locator('.atlas-detail-body h2')).to_have_text(outside,timeout=60000) expect(page.locator('.atlas-location')).to_contain_text('outside the current map sample') passed('Real full-corpus lookup resolves a protein absent from the 12,000-point sample') field.fill('../bad');page.get_by_role('button',name='Find protein',exact=False).click() expect(page.locator('.atlas-error')).to_contain_text('Enter a record ID') page.locator('.atlas-case').nth(0).click() with page.expect_download() as download: page.get_by_role('button',name='↓ FASTA',exact=True).click() assert download.value.suggested_filename.endswith('.fasta') passed('Invalid IDs show a clear error; case FASTA downloads remain available') page.goto(BASE,wait_until='domcontentloaded');page.locator('.hero').wait_for();page.locator('.hero .molecule[data-render-state="ready"]').wait_for(timeout=30000) page.evaluate('document.fonts.ready');page.screenshot(path=str(OUT/'final-home.png')) assert not page.locator('a[href*="/paper/"], img[src*="/paper/"], #paper').count() assert not any('/paper/' in url for url in requests) passed('Homepage contains no manuscript gallery, image requests or original-figure links') page.locator('#atlas').scroll_into_view_if_needed();expect(page.locator('#atlas .atlas-marker')).to_have_count(8) page.wait_for_timeout(650);page.locator('#atlas').screenshot(path=str(OUT/'final-home-atlas.png')) expect(page.locator('#atlas .atlas-map-toolbar')).to_contain_text('4,000') for i,c in enumerate(CASES): page.locator('#atlas .atlas-case').nth(i).click();expect(page.locator('.atlas-preview-story')).to_contain_text(c['uniref_id'][9:]);expect(page.locator('#atlas .atlas-marker')).to_have_count(8) passed('Homepage uses the 4,000-point asset and all eight preview stories respond') assert not page.evaluate('document.documentElement.scrollWidth>innerWidth') for width in [390,768]: page.set_viewport_size({'width':width,'height':844}) page.goto(BASE,wait_until='domcontentloaded');page.locator('.hero').wait_for();page.wait_for_timeout(500) page.screenshot(path=str(OUT/f'final-home-{width}.png')) page.locator('#atlas').scroll_into_view_if_needed();expect(page.locator('#atlas .atlas-marker')).to_have_count(8) page.wait_for_timeout(600);page.locator('#atlas').screenshot(path=str(OUT/f'final-preview-{width}.png')) assert not page.evaluate('document.documentElement.scrollWidth>innerWidth') page.goto(BASE+'/atlas',wait_until='domcontentloaded');expect(page.locator('.atlas-marker')).to_have_count(8) page.wait_for_timeout(500);page.screenshot(path=str(OUT/f'final-atlas-{width}.png'),full_page=True) page.locator('.atlas-case').nth(7).click();expect(page.locator('.atlas-detail-body h2')).to_have_text(CASES[7]['uniref_id']) assert not page.evaluate('document.documentElement.scrollWidth>innerWidth') passed('390 px phone and 768 px tablet have no horizontal overflow; case selection works') page.emulate_media(reduced_motion='reduce');page.reload(wait_until='domcontentloaded') page.locator('.atlas-marker.selected').wait_for();assert page.locator('.atlas-map-error').count()==0 passed('Reduced-motion mode preserves map and case interactions') assert not errors,errors (OUT/'browser-validation.json').write_text(json.dumps({'status':'passed','checks':checks,'page_errors':errors},indent=2)+'\n') browser.close()