feat: initial commit - Carinha Control Panel v1.0 com UI glassmorphism, watch-bar, emojis, braco robotico e conversa IA
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
"""Integration test against a running local server; browser page is the real face."""
|
||||
from playwright.sync_api import sync_playwright
|
||||
from pathlib import Path
|
||||
import importlib.util
|
||||
import tempfile
|
||||
import threading
|
||||
import sys
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT))
|
||||
spec = importlib.util.spec_from_file_location('kiosk_browser', ROOT / 'kiosk-server.py')
|
||||
kiosk = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(kiosk)
|
||||
|
||||
|
||||
def main():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
kiosk.ARQUIVO_APARENCIA = str(Path(tmp) / 'aparencia.json')
|
||||
server = kiosk.Servidor(('127.0.0.1', 0), kiosk.Handler)
|
||||
server.controle = kiosk.ControlePC(Path(tmp) / 'app.json')
|
||||
thread = threading.Thread(target=server.serve_forever, daemon=True)
|
||||
thread.start()
|
||||
try:
|
||||
browser_test('http://127.0.0.1:' + str(server.server_port))
|
||||
finally:
|
||||
server.shutdown()
|
||||
server.server_close()
|
||||
thread.join()
|
||||
|
||||
|
||||
def browser_test(base):
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.launch(headless=True)
|
||||
page = browser.new_page()
|
||||
page.goto(base + '/carinha.html?auto=0&camera=0')
|
||||
page.wait_for_selector('#tela')
|
||||
page.request.post(base + '/app/config', data={'volume': 0.65, 'sompausa': 35, 'reagir': False})
|
||||
page.wait_for_timeout(1500)
|
||||
assert page.evaluate('window.eilik.audio.volume') == 0.65, 'Volume remoto não aplicado'
|
||||
assert page.evaluate('window.eilik.ouvido().segSilencio') == 35, 'Sono remoto não aplicado'
|
||||
page.evaluate('window.eilik.movimento(0.8, 0.1, 0.5)')
|
||||
assert page.evaluate('window.eilik.presenca().olharX') == 0, 'Reação desligada precisa manter olhos no centro'
|
||||
page.request.post(base+'/app/config', data={'reagir':True})
|
||||
page.wait_for_timeout(1100)
|
||||
page.evaluate("window.eilik.soltar(); window.eilik.rastrear({tipo:'mao',x:.9,y:.5,atividade:false})")
|
||||
assert page.evaluate('window.eilik.presenca().olharX') > 20, 'Olhos devem seguir alvo em uma amostra'
|
||||
page.evaluate('window.eilik.movimento(.8,.1,.5)')
|
||||
assert page.evaluate('window.eilik.presenca().olharX') > 20, 'Detector simples não pode disputar alvo recente'
|
||||
page.wait_for_timeout(400)
|
||||
page.evaluate('window.eilik.movimento(.8,.1,.5)')
|
||||
assert page.evaluate('window.eilik.presenca().olharX') < 0, 'Alvo expirado deve liberar detector simples'
|
||||
page.evaluate("window.eilik.trata('dormir'); window.eilik.rastrear({tipo:'mao',x:.9,y:.5,atividade:true})")
|
||||
assert page.evaluate('window.eilik.face.dormindo'), 'Sono deve respeitar câmera desativada'
|
||||
page.evaluate('window.eilik.soltar()')
|
||||
page.request.post(base + '/config', data={'rosto': 'miudo', 'cor': [255, 120, 0]})
|
||||
page.wait_for_timeout(800)
|
||||
assert page.evaluate('window.eilik.rostoAtual()') == 'miudo'
|
||||
assert page.evaluate('window.eilik.face.cor') == [255, 120, 0], 'Cor deve persistir em repouso'
|
||||
page.request.post(base + '/app/config', data={'boca':False, 'sobrancelhas':True})
|
||||
page.wait_for_timeout(1200)
|
||||
assert not page.locator('#boca').is_visible(), 'Boca deve poder ser desligada'
|
||||
assert page.locator('#sobrancelha1').is_visible(), 'Sobrancelhas devem poder ser ligadas'
|
||||
panel = browser.new_page(viewport={'width': 1440, 'height': 1000})
|
||||
errors = []
|
||||
panel.on('pageerror', lambda error: errors.append(str(error) + '\n' + error.stack))
|
||||
panel.goto(base + '/painel')
|
||||
panel.wait_for_selector('#gestos button')
|
||||
panel.locator('#ajuste-sensorMic').uncheck()
|
||||
panel.wait_for_timeout(400)
|
||||
assert panel.request.get(base + '/app/config').json()['sensorMic'] is False
|
||||
panel.locator('#ajuste-cameraSono').check()
|
||||
panel.wait_for_timeout(400)
|
||||
panel.locator('#ajuste-cameraLado').select_option('environment')
|
||||
panel.wait_for_timeout(400)
|
||||
c = panel.request.get(base + '/app/config').json()
|
||||
assert c['cameraSono'] is True and c['cameraLado'] == 'environment'
|
||||
panel.get_by_role('button', name='Ligar câmera').click()
|
||||
panel.wait_for_timeout(500)
|
||||
assert panel.request.get(base + '/app/config').json()['preview'] is True
|
||||
panel.get_by_role('button', name='Desligar câmera').click()
|
||||
panel.wait_for_timeout(500)
|
||||
assert panel.request.get(base + '/app/config').json()['preview'] is False
|
||||
assert not errors, errors
|
||||
work = Path(__file__).resolve().parents[3] / 'work'
|
||||
panel.screenshot(path=str(work / 'painel-desktop.png'), full_page=True)
|
||||
panel.set_viewport_size({'width': 390, 'height': 844})
|
||||
panel.screenshot(path=str(work / 'painel-mobile.png'), full_page=True)
|
||||
assert panel.evaluate('document.documentElement.scrollWidth <= innerWidth'), 'Overflow mobile'
|
||||
browser.close()
|
||||
print('Remote config, gesture queue, camera toggle and responsive panel: OK')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user