Files
rpa_vision_v3/tests/smoke/test_smoke_e2e_minimal.py
Dom a27b74cf22 v1.0 - Version stable: multi-PC, détection UI-DETR-1, 3 modes exécution
- Frontend v4 accessible sur réseau local (192.168.1.40)
- Ports ouverts: 3002 (frontend), 5001 (backend), 5004 (dashboard)
- Ollama GPU fonctionnel
- Self-healing interactif
- Dashboard confiance

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 11:23:51 +01:00

138 lines
5.1 KiB
Python

"""
Fiche #5 - Smoke Test E2E Minimal (dry-run)
Auteur: Dom, Alice Kiro - 15 décembre 2024
Objectif: Test ultra simple qui valide le chemin critique sans cliquer pour de vrai
Valide: ScreenState + UIElements → TargetResolver → ActionExecutor (dry-run)
=> Barrière anti-régression : si ça passe, tu as le droit de respirer !
"""
import pytest
# Marquer tous les tests de ce fichier comme smoke tests
pytestmark = pytest.mark.smoke
from datetime import datetime
from core.models.screen_state import ScreenState, RawLevel, PerceptionLevel, ContextLevel, WindowContext, EmbeddingRef
from core.models.ui_element import UIElement, UIElementEmbeddings, VisualFeatures
from core.models.workflow_graph import TargetSpec, Action, ActionType, WorkflowEdge, EdgeConstraints, PostConditions
from core.execution.target_resolver import TargetResolver
from core.execution.action_executor import ActionExecutor, ExecutionStatus
from core.execution.error_handler import ErrorHandler
def _mk_elem(eid, etype, role, x, y, w, h, label, conf=0.95):
"""Helper pour créer un UIElement rapidement"""
return UIElement(
element_id=eid,
type=etype,
role=role,
bbox=(x, y, w, h), # XYWH
center=(x + w // 2, y + h // 2),
label=label,
label_confidence=1.0,
embeddings=UIElementEmbeddings(image=None, text=None),
visual_features=VisualFeatures(
dominant_color="gray",
has_icon=False,
shape="rectangle",
size_category="medium",
),
confidence=conf,
tags=[],
metadata={},
)
@pytest.fixture
def screen_state_login():
"""ScreenState de test avec écran de login"""
ui = [
_mk_elem("lbl_user", "label", "data_display", 100, 100, 120, 20, "Username"),
_mk_elem("inp_user", "text_input", "form_input", 240, 95, 260, 30, ""),
_mk_elem("lbl_pass", "label", "data_display", 100, 160, 120, 20, "Password"),
_mk_elem("inp_pass", "text_input", "form_input", 240, 155, 260, 30, ""),
_mk_elem("btn_signin", "button", "submit", 240, 220, 140, 35, "Sign in"),
]
return ScreenState(
screen_state_id="ss_login_001",
timestamp=datetime.now(),
session_id="sess_001",
window=WindowContext(app_name="TestApp", window_title="Login", screen_resolution=[1920, 1080]),
raw=RawLevel(screenshot_path="N/A", capture_method="test", file_size_bytes=0),
perception=PerceptionLevel(
embedding=EmbeddingRef(provider="test", vector_id="N/A", dimensions=1),
detected_text=["Username", "Password", "Sign in"],
text_detection_method="test",
confidence_avg=1.0,
),
context=ContextLevel(user_id="test_user"),
ui_elements=ui,
)
def test_smoke_resolver_by_text(screen_state_login):
"""Test que TargetResolver trouve un élément par texte"""
r = TargetResolver()
t = TargetSpec(by_text="Sign in")
resolved = r.resolve_target(t, screen_state_login)
assert resolved is not None
assert resolved.element.element_id == "btn_signin"
def test_smoke_executor_click_dry_run(monkeypatch, tmp_path, screen_state_login):
"""Test ActionExecutor clic en mode dry-run (sans cliquer pour de vrai)"""
# Force no real click + no sleep
import core.execution.action_executor as ae
monkeypatch.setattr(ae, "PYAUTOGUI_AVAILABLE", False)
monkeypatch.setattr(ae.time, "sleep", lambda *_: None)
err = ErrorHandler(error_log_dir=str(tmp_path / "errors"))
ex = ActionExecutor(error_handler=err, verify_postconditions=False)
edge = WorkflowEdge(
edge_id="e1",
from_node="n0",
to_node="n1",
action=Action(
type=ActionType.MOUSE_CLICK,
target=TargetSpec(by_text="Sign in"),
parameters={"wait_after_ms": 0},
),
constraints=EdgeConstraints(),
post_conditions=PostConditions(),
)
res = ex.execute_edge(edge, screen_state_login)
assert res.status == ExecutionStatus.SUCCESS
assert res.target_resolved is not None
assert res.target_resolved.element.element_id == "btn_signin"
def test_smoke_executor_text_input_dry_run(monkeypatch, tmp_path, screen_state_login):
"""Test ActionExecutor saisie de texte en mode dry-run"""
import core.execution.action_executor as ae
monkeypatch.setattr(ae, "PYAUTOGUI_AVAILABLE", False)
monkeypatch.setattr(ae.time, "sleep", lambda *_: None)
err = ErrorHandler(error_log_dir=str(tmp_path / "errors"))
ex = ActionExecutor(error_handler=err, verify_postconditions=False)
edge = WorkflowEdge(
edge_id="e2",
from_node="n0",
to_node="n0",
action=Action(
type=ActionType.TEXT_INPUT,
target=TargetSpec(by_role="form_input", selection_policy="first"),
parameters={"text": "hello", "wait_after_ms": 0},
),
constraints=EdgeConstraints(),
post_conditions=PostConditions(),
)
res = ex.execute_edge(edge, screen_state_login)
assert res.status == ExecutionStatus.SUCCESS
assert res.target_resolved is not None