our_knp/pets-knp/check_browser.py

43 lines
4.6 KiB
Python

"""Chromium fallback after T3 preview explicitly reported no automation host."""
import subprocess,tempfile,time,json,urllib.request,base64,shutil
from pathlib import Path
import websocket
O=Path('/opt/neiro/reports/pets-knp-artifacts');O.mkdir(exist_ok=True);profile=tempfile.mkdtemp(prefix='pets-cdp-');log=(O/'chromium.log').open('w');p=subprocess.Popen(['chromium','--headless','--no-sandbox','--disable-gpu','--remote-debugging-port=9342','--remote-allow-origins=*','--user-data-dir='+profile,'about:blank'],stdout=log,stderr=log);ws=None;counter=0;errors=[]
try:
for _ in range(50):
try:pages=json.load(urllib.request.urlopen('http://127.0.0.1:9342/json',timeout=1));break
except Exception:time.sleep(.1)
ws=websocket.create_connection(next(a['webSocketDebuggerUrl'] for a in pages if a['type']=='page'),timeout=30)
def call(method,params=None):
global counter
counter+=1;want=counter;ws.send(json.dumps({'id':want,'method':method,'params':params or {}}))
while True:
msg=json.loads(ws.recv())
if msg.get('method')=='Runtime.exceptionThrown':errors.append(msg['params'])
if msg.get('id')==want:
if 'error' in msg:raise RuntimeError(msg['error'])
return msg.get('result',{})
def js(expr,wait=False):
out=call('Runtime.evaluate',{'expression':expr,'returnByValue':True,'awaitPromise':wait})
if 'exceptionDetails' in out:raise RuntimeError(out['exceptionDetails'])
return out['result'].get('value')
def until(expr):return js('new Promise((resolve,reject)=>{let n=0;let t=setInterval(()=>{if('+expr+'){clearInterval(t);resolve(true)}else if(++n>200){clearInterval(t);reject(Error("wait timeout"))}},50)})',True)
call('Page.enable');call('Runtime.enable');call('Emulation.setDeviceMetricsOverride',{'width':1440,'height':1100,'deviceScaleFactor':1,'mobile':False});call('Page.navigate',{'url':'http://10.9.8.230:8082/'})
until("document.querySelectorAll('.sample').length===24&&document.querySelector('#accuracy').textContent.includes('%')")
js("document.querySelector('.sample').click()");until("!busy&&document.querySelector('#status').textContent.includes('ГОТОВО')")
first=js("({answer:document.querySelector('#answer').textContent,status:document.querySelector('#status').textContent,subtitle:document.querySelector('#subtitle').textContent,overflow:document.documentElement.scrollWidth>innerWidth})");assert not first['overflow']
shot=call('Page.captureScreenshot',{'format':'png','captureBeyondViewport':True});(O/'pets-desktop.png').write_bytes(base64.b64decode(shot['data']))
# Native file picker input using a real local file, then classify the image.
samples=json.load(urllib.request.urlopen('http://10.9.8.230:8082/api/samples'));file=O/'upload-test.png';file.write_bytes(base64.b64decode(samples[1]['image'].split(',')[1]));doc=call('DOM.getDocument');node=call('DOM.querySelector',{'nodeId':doc['root']['nodeId'],'selector':'#file'})['nodeId'];call('DOM.setFileInputFiles',{'nodeId':node,'files':[str(file)]});until('truth===null&&current!==null&&!busy');js("document.querySelector('#run').click()");until("!busy&&document.querySelector('#status').textContent.includes('ГОТОВО')")
upload=js("({answer:document.querySelector('#answer').textContent,subtitle:document.querySelector('#subtitle').textContent,hasInput:document.querySelector('#tiny').src.startsWith('data:image/png')})");assert upload['hasInput']
call('Emulation.setDeviceMetricsOverride',{'width':390,'height':844,'deviceScaleFactor':1,'mobile':True});time.sleep(.2);mobile=js("({overflow:document.documentElement.scrollWidth>innerWidth,samples:document.querySelectorAll('.sample').length})");assert not mobile['overflow'];shot=call('Page.captureScreenshot',{'format':'png','captureBeyondViewport':True});(O/'pets-mobile.png').write_bytes(base64.b64decode(shot['data']))
# Select a new picture while an old request is running: old answer must not overwrite it.
js("document.querySelector('#run').click();select(document.querySelector('.sample img').src,null)");until('!busy');stale=js("({answer:document.querySelector('#answer').textContent,status:document.querySelector('#status').textContent})");assert stale['answer']=='Готовы?'
assert not errors,errors
(O/'browser-checks.json').write_text(json.dumps({'desktop':first,'file_upload':upload,'mobile':mobile,'stale_response_ignored':True,'javascript_errors':errors},ensure_ascii=False,indent=2));print(json.dumps({'browser_checked':True,'javascript_errors':len(errors),'mobile_overflow':mobile['overflow']}))
finally:
if ws:ws.close()
p.terminate()
try:p.wait(timeout=5)
except subprocess.TimeoutExpired:p.kill();p.wait()
log.close();shutil.rmtree(profile,ignore_errors=True)