Download scripts/browser_display_check.py from lvwerra/starmap: direct link, hf CLI and curl.
- Browser
- Download file 9.82 kB
-
https://huggingface.co/spaces/lvwerra/starmap/resolve/main/scripts/browser_display_check.py
- Command line
-
hf download hf://spaces/lvwerra/starmap/scripts/browser_display_check.py
-
curl -L -o browser_display_check.py https://huggingface.co/spaces/lvwerra/starmap/resolve/main/scripts/browser_display_check.py
9.82 kB
| """Exercise themes, faint-star selection, 10 Hz painting and the curved Observer view.""" | |
| import asyncio,math,os,statistics | |
| from pathlib import Path | |
| from playwright.async_api import async_playwright | |
| from PIL import Image | |
| OUTPUT=Path(os.environ.get('SIDEREAL_TEST_OUTPUT','/tmp/sidereal-display-check')) | |
| OUTPUT.mkdir(parents=True,exist_ok=True) | |
| async def main(): | |
| async with async_playwright() as p: | |
| browser=await p.chromium.launch(headless=True,executable_path=os.environ.get('CHROMIUM_EXECUTABLE','/opt/pw-browsers/chromium-1234/chrome-linux64/chrome'),args=['--no-sandbox']) | |
| page=await browser.new_page(viewport={'width':1440,'height':1000}) | |
| errors=[];page.on('pageerror',lambda e:errors.append(str(e))) | |
| await page.add_init_script(""" | |
| localStorage.setItem('sidereal-site',JSON.stringify({name:'Bern',lat:46.948,lon:7.4474,elevation:540})); | |
| window.drawTimes=[];window.starDots=[]; | |
| const clear=CanvasRenderingContext2D.prototype.clearRect,arc=CanvasRenderingContext2D.prototype.arc; | |
| CanvasRenderingContext2D.prototype.clearRect=function(...args){if(!this.canvas.classList.contains('map-overlay')){window.drawTimes.push(performance.now());window.drawTimes=window.drawTimes.slice(-500);window.starDots=[];}return clear.apply(this,args)}; | |
| CanvasRenderingContext2D.prototype.arc=function(x,y,r,...rest){if(r>=.85&&r<=1.2&&!this.canvas.classList.contains('map-overlay'))window.starDots.push({x,y,r,color:this.fillStyle});return arc.call(this,x,y,r,...rest)}; | |
| """) | |
| base=os.environ.get('SIDEREAL_TEST_URL','http://127.0.0.1:7866') | |
| if 'hf.space' in base: | |
| async def auth(route):await route.continue_(headers={**route.request.headers,'Authorization':'Bearer '+os.environ['HF_TOKEN']}) | |
| await page.route('https://lvwerra-sidereal.hf.space/**',auth) | |
| await page.goto(base,wait_until='networkidle') | |
| date=page.get_by_label('Observing date and time in Europe/Zurich') | |
| await date.fill('2026-09-06T22:00') | |
| await page.get_by_label('Search sky objects').fill('Vega') | |
| await page.locator('.search-results button').first.click() | |
| slider=page.get_by_label('Faintest displayed star magnitude') | |
| await slider.fill('14') | |
| await page.get_by_role('button',name='ZOOM FOR FAINT STARS',exact=False).click() | |
| await page.wait_for_function("document.querySelector('.deep-star-status')?.textContent.includes('Dense field') || document.querySelector('.deep-star-status')?.textContent.includes('Gaia field loaded')",timeout=45000) | |
| initial=await page.locator('.sky-canvas').bounding_box() | |
| await page.mouse.move(initial['x']+initial['width']/2,initial['y']+initial['height']/2) | |
| await page.mouse.wheel(0,math.log(.2)/.0015) | |
| await page.wait_for_function("document.querySelector('.deep-star-status')?.textContent.includes('Gaia field loaded')",timeout=45000) | |
| await page.wait_for_timeout(100) | |
| dots=await page.evaluate('window.starDots') | |
| assert len(dots)>100 and min(d['r'] for d in dots)>1.1 | |
| assert any(d['color']=='#62665c' for d in dots) | |
| await page.screenshot(path=str(OUTPUT/'faint-light.png')) | |
| await page.get_by_role('button',name='Switch to dark mode',exact=True).click() | |
| assert await page.locator('html').get_attribute('data-theme')=='dark' | |
| assert await page.evaluate('getComputedStyle(document.documentElement).backgroundColor')=='rgb(20, 21, 19)' | |
| assert await page.evaluate("window.starDots.some(p=>p.color==='#c4c8bb')") | |
| await page.wait_for_timeout(200) | |
| await page.screenshot(path=str(OUTPUT/'faint-dark.png')) | |
| host=page.locator('.sky-canvas');box=await host.bounding_box() | |
| await page.mouse.move(box['x']+5,box['y']+60) | |
| assert 'crosshair' in await host.evaluate('(e)=>getComputedStyle(e).cursor') | |
| selected=False | |
| for dot in dots[::max(1,len(dots)//40)]: | |
| if not(50<dot['x']<box['width']-50 and 50<dot['y']<box['height']-50):continue | |
| x,y=box['x']+dot['x'],box['y']+dot['y'] | |
| await page.mouse.move(x,y) | |
| tooltip=page.get_by_role('tooltip') | |
| if await tooltip.count() and 'Gaia DR3' in await tooltip.inner_text(): | |
| assert 'crosshair' in await host.evaluate('(e)=>getComputedStyle(e).cursor') | |
| name=await tooltip.locator('strong').inner_text() | |
| await page.mouse.down() | |
| assert await host.evaluate('(e)=>getComputedStyle(e).cursor')!='grabbing' | |
| await page.mouse.up() | |
| assert await page.locator('.object-heading h2').inner_text()==name | |
| selected=True;break | |
| assert selected | |
| await page.mouse.move(box['x']+box['width']/2,box['y']+box['height']/2) | |
| await page.mouse.down() | |
| await page.mouse.move(box['x']+box['width']/2+50,box['y']+box['height']/2+20,steps=4) | |
| assert 'crosshair' in await host.evaluate('(e)=>getComputedStyle(e).cursor') | |
| await page.mouse.up() | |
| assert await host.evaluate('(e)=>getComputedStyle(e).cursor')!='grabbing' | |
| await page.get_by_role('button',name='ALL SKY',exact=True).click() | |
| await page.get_by_role('button',name='Play time',exact=True).click() | |
| await page.wait_for_timeout(500) | |
| await page.evaluate('window.drawTimes=[]') | |
| await page.wait_for_timeout(3000) | |
| draws=await page.evaluate('window.drawTimes') | |
| median=statistics.median(b-a for a,b in zip(draws,draws[1:])) | |
| assert 26<=len(draws)<=35,(len(draws),median) | |
| assert 80<median<125,median | |
| await page.get_by_role('button',name='Pause time',exact=True).click() | |
| await page.wait_for_timeout(500) | |
| await page.evaluate('window.drawTimes=[]') | |
| await page.wait_for_timeout(350) | |
| assert not await page.evaluate('window.drawTimes') | |
| await page.reload(wait_until='networkidle') | |
| assert await page.locator('html').get_attribute('data-theme')=='dark' | |
| await slider.fill('6.5') | |
| await date.fill('2026-09-06T14:00') | |
| await page.wait_for_timeout(300) | |
| await page.get_by_label('Search sky objects').fill('Sun') | |
| await page.locator('.search-results button').first.click() | |
| await page.get_by_role('button',name='OBSERVER VIEW',exact=True).click() | |
| await page.wait_for_function("document.querySelector('.terrain-controls span')?.textContent === ''",timeout=30000) | |
| await page.screenshot(path=str(OUTPUT/'personal-dark.png')) | |
| await page.get_by_role('button',name='Switch to light mode',exact=True).click() | |
| await page.wait_for_timeout(200) | |
| await page.screenshot(path=str(OUTPUT/'personal-light.png')) | |
| # The Sun's actual half-degree limb must remain round in a close personal view. | |
| await page.get_by_role('button',name='Switch to dark mode',exact=True).click() | |
| for _ in range(6):await page.get_by_role('button',name='Zoom in',exact=True).click() | |
| await page.get_by_role('button',name='CENTRE IN SKY VIEW',exact=True).click() | |
| await page.wait_for_timeout(100) | |
| await host.screenshot(path=str(OUTPUT/'personal-sun.png')) | |
| im=Image.open(OUTPUT/'personal-sun.png').convert('RGB') | |
| points=[(x,y) for y in range(im.height) for x in range(im.width) if im.getpixel((x,y))==(236,236,218)] | |
| assert len(points)>100,'Sun pixels missing' | |
| width=max(x for x,y in points)-min(x for x,y in points)+1 | |
| height=max(y for x,y in points)-min(y for x,y in points)+1 | |
| assert abs(width/height-1)<.05,(width,height) | |
| # Moon selection, cursor-anchored zoom and the simulated field use the same projection. | |
| await date.fill('2026-09-06T08:00') | |
| await page.wait_for_timeout(300) | |
| await page.get_by_label('Search sky objects').fill('Moon') | |
| await page.locator('.search-results button').first.click() | |
| async def moon_bounds(): | |
| await page.wait_for_timeout(150) | |
| await host.screenshot(path=str(OUTPUT/'personal-moon.png')) | |
| im=Image.open(OUTPUT/'personal-moon.png').convert('RGB') | |
| points=[(x,y) for y in range(im.height) for x in range(im.width) if im.getpixel((x,y))==(155,163,146)] | |
| assert len(points)>100,'Moon pixels missing' | |
| left,right=min(x for x,y in points),max(x for x,y in points) | |
| top,bottom=min(y for x,y in points),max(y for x,y in points) | |
| assert abs((right-left+1)/(bottom-top+1)-1)<.05,(left,right,top,bottom) | |
| return ((left+right)/2,(top+bottom)/2) | |
| moon=await moon_bounds() | |
| box=await host.bounding_box() | |
| await page.mouse.move(box['x']+moon[0]+60,box['y']+moon[1]+50) | |
| await page.mouse.down() | |
| await page.mouse.move(box['x']+moon[0]+120,box['y']+moon[1]+70,steps=5) | |
| await page.mouse.up() | |
| moon=await moon_bounds() | |
| await page.mouse.move(box['x']+moon[0],box['y']+moon[1]) | |
| await page.mouse.wheel(0,-140) | |
| after=await moon_bounds() | |
| assert abs(after[0]-moon[0])<1.5 and abs(after[1]-moon[1])<1.5,(moon,after) | |
| await page.get_by_role('button',name='TELESCOPE',exact=True).click() | |
| await page.get_by_role('button',name='CONNECT SIMULATOR',exact=False).click() | |
| await page.get_by_role('button',name='SLEW TO OBJECT',exact=False).click() | |
| await page.wait_for_function("document.querySelector('.sim-label')?.textContent === 'SIMULATING TRACKING'",timeout=45000) | |
| await page.get_by_role('button',name='ZOOM TO FIELD',exact=False).click() | |
| await page.wait_for_timeout(200) | |
| assert await page.locator('.map-overlay').evaluate('(c)=>{const d=c.getContext("2d").getImageData(0,0,c.width,c.height).data;let n=0;for(let i=3;i<d.length;i+=4)if(d[i])n++;return n>100}') | |
| await page.screenshot(path=str(OUTPUT/'personal-telescope.png')) | |
| await page.get_by_role('button',name='DISCONNECT SIMULATOR',exact=False).click() | |
| for width in [820,390,320]: | |
| await page.set_viewport_size({'width':width,'height':844}) | |
| assert not await page.evaluate('document.documentElement.scrollWidth>innerWidth') | |
| assert await page.get_by_role('button',name='Switch to light mode',exact=True).is_visible() | |
| await page.screenshot(path=str(OUTPUT/f'dark-mobile-{width}.png')) | |
| assert not errors,errors | |
| print(f'PASSED {base}: faint-star size/contrast; light/dark canvas; persistent theme; forced crosshair; {len(draws)} redraws in 3 seconds, median {median:.1f} ms; pause; curved terrain; round Sun and Moon; cursor zoom; simulated field; responsive layout. Errors: {errors}') | |
| await browser.close() | |
| asyncio.run(main()) | |