"""Tests para whatsapp_send_image. whatsapp_send_image compone whatsapp_open_chat con tres primitivas CDP (cdp_eval, cdp_click_xy, cdp_set_file_input) y `whatsapp_send_message` (para el caption de seguimiento), y requiere un Chrome vivo. Aqui se mockean todas con monkeypatch sobre el modulo `browser.whatsapp_send_image` (donde quedan ligados los nombres por el `from browser.X import Y`), de modo que NO hace falta Chrome. El fake de cdp_eval distingue cada expresion por un marcador de comentario JS embebido en ella (`/*ADJUNTAR*/`, `/*PREVIEW*/`, `/*SEND*/`, `/*LABEL*/`). El estado `after_send` (que /*SEND*/ activa) hace que /*PREVIEW*/ devuelva 0 adjuntos tras el envio de la imagen, simulando el cierre de la bandeja. """ import json import os import sys sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) import browser.whatsapp_send_image as wsi # noqa: E402 from browser.whatsapp_send_image import whatsapp_send_image # noqa: E402 # Imagen real para pasar la validacion de existencia (este propio archivo de test). _IMG = os.path.abspath(__file__) class _Spy: def __init__(self, ret=None): self.calls = [] self.ret = ret if ret is not None else {"ok": True} def __call__(self, *args, **kwargs): self.calls.append((args, kwargs)) return self.ret def _make_eval(label="Escribir un mensaje para el grupo NOTAS WASAP", state=None): state = state if state is not None else {} def fake(expr, *, port=9222, target_url_substr=""): if "/*ADJUNTAR*/" in expr: return {"ok": True, "value": json.dumps({"x": 575, "y": 589}), "error": ""} if "/*SEND*/" in expr: state["after_send"] = True return {"ok": True, "value": json.dumps({"x": 1136, "y": 578}), "error": ""} if "/*PREVIEW*/" in expr: return {"ok": True, "value": 0 if state.get("after_send") else 1, "error": ""} if "/*LABEL*/" in expr: return {"ok": True, "value": label, "error": ""} return {"ok": True, "value": None, "error": ""} return fake def _patch_common(monkeypatch, *, eval_fn, set_ret={"ok": True}, open_ret=None, send_msg_ret={"sent": True}): open_spy = _Spy(ret=open_ret if open_ret is not None else {"opened": True, "name": "x"}) click_spy = _Spy(ret={"ok": True}) set_spy = _Spy(ret=set_ret) sendmsg_spy = _Spy(ret=send_msg_ret) monkeypatch.setattr(wsi, "whatsapp_open_chat", open_spy) monkeypatch.setattr(wsi, "cdp_eval", eval_fn) monkeypatch.setattr(wsi, "cdp_click_xy", click_spy) monkeypatch.setattr(wsi, "cdp_set_file_input", set_spy) monkeypatch.setattr(wsi, "whatsapp_send_message", sendmsg_spy) monkeypatch.setattr(wsi.time, "sleep", lambda *a, **k: None) return open_spy, click_spy, set_spy, sendmsg_spy def test_golden_envia_imagen_y_caption_de_seguimiento(monkeypatch): cap = "item icon: potion" state = {} open_spy, click_spy, set_spy, sendmsg_spy = _patch_common( monkeypatch, eval_fn=_make_eval(state=state)) res = whatsapp_send_image("NOTAS WASAP", _IMG, caption=cap, port=9222, target_url_substr="whatsapp") assert res["sent"] is True and res["ok"] is True assert res["caption_sent"] is True assert res["recipient"] == "NOTAS WASAP" assert res["image"] == _IMG assert res["caption"] == cap assert res["error"] == "" # Se adjunto la imagen (ruta absoluta) por setFileInputFiles. assert set_spy.calls[0][0][0] == 'input[type="file"][multiple]' assert set_spy.calls[0][0][1] == _IMG # Dos clicks reales: Adjuntar y Enviar (bandeja). assert len(click_spy.calls) == 2 # El caption viaja como mensaje de texto de seguimiento, open_first=False. assert len(sendmsg_spy.calls) == 1 assert sendmsg_spy.calls[0][0][0] == "NOTAS WASAP" assert sendmsg_spy.calls[0][0][1] == cap assert sendmsg_spy.calls[0][1].get("open_first") is False def test_envia_sin_caption_no_manda_texto(monkeypatch): state = {} _, click_spy, set_spy, sendmsg_spy = _patch_common( monkeypatch, eval_fn=_make_eval(state=state)) res = whatsapp_send_image("NOTAS WASAP", _IMG, caption="", port=9222, target_url_substr="whatsapp") assert res["sent"] is True assert res["caption_sent"] is False # Sin caption: NO se manda mensaje de texto de seguimiento. assert len(sendmsg_spy.calls) == 0 assert len(click_spy.calls) == 2 def test_edge_imagen_no_existe_error_sin_abrir(monkeypatch): open_spy, click_spy, set_spy, sendmsg_spy = _patch_common( monkeypatch, eval_fn=_make_eval()) res = whatsapp_send_image("NOTAS WASAP", "/no/existe/foo.png", port=9222, target_url_substr="whatsapp") assert res["sent"] is False and res["ok"] is False assert "no encontrada" in res["error"] # Ni siquiera se intento abrir el chat ni adjuntar. assert len(open_spy.calls) == 0 assert len(set_spy.calls) == 0 def test_edge_open_fallido_error_sin_adjuntar(monkeypatch): open_spy, click_spy, set_spy, sendmsg_spy = _patch_common( monkeypatch, eval_fn=_make_eval(), open_ret={"opened": False, "name": "x", "reason": "chat no encontrado en la lista (no cargado o nombre inexacto)"}) res = whatsapp_send_image("Inexistente", _IMG, port=9222, target_url_substr="whatsapp") assert res["sent"] is False assert "no encontrado" in res["error"] # No se adjunto ni se hizo click cuando el chat no abrio. assert len(set_spy.calls) == 0 assert len(click_spy.calls) == 0 def test_seguridad_open_first_false_label_no_coincide_aborta(monkeypatch): open_spy, click_spy, set_spy, sendmsg_spy = _patch_common( monkeypatch, eval_fn=_make_eval(label="Escribir un mensaje para el grupo OTRO CHAT")) res = whatsapp_send_image("NOTAS WASAP", _IMG, port=9222, target_url_substr="whatsapp", open_first=False) assert res["sent"] is False assert "abortado por seguridad" in res["error"] # SEGURIDAD: no se adjunto ni se clicko nada. assert len(set_spy.calls) == 0 assert len(click_spy.calls) == 0 def test_error_set_file_input_falla_no_envia(monkeypatch): state = {} open_spy, click_spy, set_spy, sendmsg_spy = _patch_common( monkeypatch, eval_fn=_make_eval(state=state), set_ret={"ok": False, "error": "no element matches selector"}) res = whatsapp_send_image("NOTAS WASAP", _IMG, port=9222, target_url_substr="whatsapp") assert res["sent"] is False assert "no se pudo adjuntar" in res["error"] # Se intento adjuntar (dos selectores) pero no se llego a enviar (solo el click de Adjuntar). assert len(set_spy.calls) == 2 assert len(click_spy.calls) == 1 assert len(sendmsg_spy.calls) == 0