File size: 3,669 Bytes
cba18a0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c5eee7b
cba18a0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
from pathlib import Path
import sys,json
sys.path.insert(0,'/home/node/local/carbon-a-render/python')
from playwright.sync_api import sync_playwright
R=Path(__file__).parent
with sync_playwright() as p:
 b=p.chromium.launch(executable_path='/opt/pw-browsers/chromium_headless_shell-1234/chrome-headless-shell-linux64/chrome-headless-shell',args=['--no-sandbox','--enable-webgl','--use-gl=angle','--use-angle=swiftshader','--enable-unsafe-swiftshader'])
 page=b.new_page(viewport={'width':1500,'height':1050},has_touch=True);errors=[];page.on('pageerror',lambda e:errors.append(str(e)))
 page.goto((R/'index.html').as_uri());page.wait_for_function('window.POC && !document.querySelector("#loading")')
 def point(i,r=62):
  return page.evaluate('''([i,radius])=>{const a=leaves[i],p=screen(polar(radius,a.angle)),box=stage.getBoundingClientRect();return {x:box.x+p[0],y:box.y+p[1],id:a.accession}}''',[i,r])
 # Hit the same exact assembly from different radii inside all four dial sectors.
 targets=[1000,11000,21500,32000]
 for i in targets:
  for radius in [35,78]:
   q=point(i,radius);page.mouse.move(q['x'],q['y']);page.wait_for_function('(i)=>selected?.i===i',arg=i)
   assert page.locator('#selection').is_visible()
   assert page.locator('#sel-id').inner_text()==q['id']
   assert page.locator('#tree').evaluate('e=>getComputedStyle(e).cursor')=='pointer'
   assert page.evaluate('pinnedAssembly===null')
 q=point(11000);page.mouse.click(q['x'],q['y']);page.mouse.move(100,100)
 assert page.evaluate('pinnedAssembly.i')==11000
 assert page.locator('#selection').is_visible()
 # A dial drag changes angle/selection while preserving the camera, even if it
 # leaves the dial. Releasing keeps the chosen assembly pinned.
 page.mouse.click(100,130)  # release the earlier frozen selection
 a=point(1000);z=point(21500,112);camera=page.evaluate('({zoom,pan:{...pan}})')
 page.mouse.move(a['x'],a['y']);page.mouse.down();page.mouse.move(z['x'],z['y'],steps=8);page.mouse.up()
 assert page.evaluate('pinnedAssembly.i')==21500
 assert page.evaluate('({zoom,pan})')==camera
 page.screenshot(path=str(R/'dial-selection.png'))
 # The mapping stays in tree coordinates under zoom and pan.
 page.evaluate('''()=>{clearSelection();zoom=2.5;pan={x:-80,y:65};draw()}''')
 q=point(32000);page.mouse.move(q['x'],q['y']);page.wait_for_function('selected?.i===32000')
 page.mouse.click(q['x'],q['y']);assert page.evaluate('pinnedAssembly.i')==32000
 # Touch taps can select through the centre as well.
 page.locator('#reset').click();page.locator('#theme-toggle').click();q=point(7000)
 page.touchscreen.tap(q['x'],q['y']);assert page.evaluate('pinnedAssembly.i')==7000
 # The top seam resolves to a real neighbouring strand; the pivot stays stable.
 seam=page.evaluate('''()=>{const right=screen(polar(60,NOON+.01)),left=screen(polar(60,NOON-.01)),centre=screen([0,0]);return [hitDial(...right)?.i,hitDial(...left)?.i,hitDial(...centre)]}''')
 assert seam==[0,33587,None],seam
 # Taking over with the dial stops playback and keeps the partial sweep totals.
 page.locator('#animate-sweep').click();page.wait_for_function('sweep.count>100')
 q=point(17000);page.mouse.click(q['x'],q['y']);assert not page.evaluate('sweep.running');assert page.evaluate('pinnedAssembly.i')==17000
 before=page.evaluate('sweep.count');page.wait_for_timeout(150);assert page.evaluate('sweep.count')==before
 assert page.evaluate('SWEEP_DURATION')==4000
 assert not errors,errors
 print(json.dumps({'dial_hover':'8 positions passed','pin':'passed','dial_drag_without_pan':'passed','zoom_and_pan':'passed','touch':'passed','top_seam':seam,'sweep_takeover':'passed','errors':errors}),flush=True)
 b.close()