import pytest from fastapi import FastAPI from fastapi.testclient import TestClient from app.auth import exigir_login from app.routers import contatos as router_contatos from app.routers import clientes as router_clientes app_teste = FastAPI() app_teste.include_router(router_clientes.router) app_teste.include_router(router_contatos.router) app_teste.dependency_overrides[exigir_login] = lambda: "teste" client = TestClient(app_teste, follow_redirects=False) # Este app de teste não tem o middleware de CSRF (só o main.py real o monta). # Simula um navegador que já tem o cookie definido: os testes de POST # precisam mandar o mesmo valor no campo oculto "csrf_token". CSRF_TESTE = "teste-csrf-token" client.cookies.set("csrf_token", CSRF_TESTE) @pytest.fixture(autouse=True) def _sem_log_real(monkeypatch): """Os routers registram cada ação em LOG_PAINEL — sem no-op, bateria no banco real.""" monkeypatch.setattr(router_contatos.db_log, "registrar", lambda *args, **kwargs: None) monkeypatch.setattr(router_clientes.db_log, "registrar", lambda *args, **kwargs: None) def test_adicionar_contato_com_sucesso(monkeypatch): monkeypatch.setattr(router_contatos.db_clientes, "obter_cliente", lambda cid: {"ID": cid, "CODIGO": "000001"}) monkeypatch.setattr(router_contatos.db_contatos, "contato_duplicado", lambda cid, tel, ignorar_id=None: False) chamadas = {} monkeypatch.setattr( router_contatos.db_contatos, "inserir_contato", lambda cid, nome, tel, email=None: chamadas.setdefault("dados", (cid, nome, tel, email)), ) resposta = client.post( "/clientes/1/contatos", data={"nome": "Fulano", "telefone": "(75) 99909-0001", "csrf_token": CSRF_TESTE} ) assert resposta.status_code == 303 # DDI 55 sempre embutido — é esse valor que o workflow n8n de envio de # chave por WhatsApp lê direto de CLIENTE_CONTATO.TELEFONE, sem # normalizar nada (ver comentário no topo de app/routers/contatos.py). assert chamadas["dados"] == (1, "Fulano", "5575999090001", None) def test_adicionar_contato_duplicado_avisa(monkeypatch): monkeypatch.setattr(router_contatos.db_clientes, "obter_cliente", lambda cid: {"ID": cid, "CODIGO": "000001"}) monkeypatch.setattr(router_contatos.db_contatos, "contato_duplicado", lambda cid, tel, ignorar_id=None: True) # Also mock the clientes router's db functions for the redirect monkeypatch.setattr(router_clientes.db_clientes, "obter_cliente", lambda cid: {"ID": cid, "CODIGO": "000001", "RAZAO": "Cliente", "FANTASIA": "Cliente"}) monkeypatch.setattr(router_clientes.db_contatos, "listar_contatos_por_cliente", lambda cid: []) monkeypatch.setattr(router_clientes.db_chaves, "status_chaves", lambda codigo: None) resposta = client.post( "/clientes/1/contatos", data={"nome": "Fulano", "telefone": "75999090001", "csrf_token": CSRF_TESTE}, follow_redirects=True, ) assert "já está cadastrado" in resposta.text def test_editar_contato_com_sucesso(monkeypatch): monkeypatch.setattr(router_contatos.db_contatos, "contato_duplicado", lambda cid, tel, ignorar_id=None: False) chamadas = {} monkeypatch.setattr( router_contatos.db_contatos, "atualizar_contato", lambda contato_id, cid, nome, tel, email=None: chamadas.setdefault( "dados", (contato_id, cid, nome, tel, email) ), ) resposta = client.post( "/clientes/1/contatos/5/editar", data={ "nome": "Fulano Editado", "telefone": "(75) 99909-0002", "email": "fulano@example.com", "csrf_token": CSRF_TESTE, }, ) assert resposta.status_code == 303 assert chamadas["dados"] == (5, 1, "Fulano Editado", "5575999090002", "fulano@example.com") def test_editar_contato_inexistente_avisa_e_nao_finge_sucesso(monkeypatch): # atualizar_contato retorna False quando o WHERE (ID + CLIENTE_ID) não # bate com nenhuma linha — ID errado, ou de outro cliente. monkeypatch.setattr(router_contatos.db_contatos, "contato_duplicado", lambda cid, tel, ignorar_id=None: False) monkeypatch.setattr(router_contatos.db_contatos, "atualizar_contato", lambda *a, **k: False) registros = [] monkeypatch.setattr( router_contatos.db_log, "registrar", lambda *args, **kwargs: registros.append(args) ) resposta = client.post( "/clientes/1/contatos/999/editar", data={"nome": "Fulano", "telefone": "75999090002", "csrf_token": CSRF_TESTE}, follow_redirects=False, ) assert resposta.status_code == 303 assert "mensagem_tipo=danger" in resposta.headers["location"] assert registros[-1][4] is False # sucesso=False no log (args: usuario, acao, entidade, entidade_id, sucesso, detalhe) def test_editar_contato_duplicado_avisa(monkeypatch): monkeypatch.setattr(router_contatos.db_contatos, "contato_duplicado", lambda cid, tel, ignorar_id=None: True) monkeypatch.setattr(router_clientes.db_clientes, "obter_cliente", lambda cid: {"ID": cid, "CODIGO": "000001", "RAZAO": "Cliente", "FANTASIA": "Cliente"}) monkeypatch.setattr(router_clientes.db_contatos, "listar_contatos_por_cliente", lambda cid: []) monkeypatch.setattr(router_clientes.db_chaves, "status_chaves", lambda codigo: None) resposta = client.post( "/clientes/1/contatos/5/editar", data={"nome": "Fulano", "telefone": "75999090001", "csrf_token": CSRF_TESTE}, follow_redirects=True, ) assert "já está cadastrado" in resposta.text def test_excluir_contato(monkeypatch): monkeypatch.setattr(router_contatos.db_clientes, "obter_cliente", lambda cid: {"ID": cid, "CODIGO": "000001"}) chamadas = {} monkeypatch.setattr( router_contatos.db_contatos, "excluir_contato", lambda contato_id, cid: chamadas.setdefault("dados", (contato_id, cid)) ) resposta = client.post("/clientes/1/contatos/5/excluir", data={"csrf_token": CSRF_TESTE}) assert resposta.status_code == 303 assert chamadas["dados"] == (5, 1) def test_excluir_contato_inexistente_avisa_e_nao_finge_sucesso(monkeypatch): monkeypatch.setattr(router_contatos.db_contatos, "excluir_contato", lambda *a, **k: False) registros = [] monkeypatch.setattr( router_contatos.db_log, "registrar", lambda *args, **kwargs: registros.append(args) ) resposta = client.post("/clientes/1/contatos/999/excluir", data={"csrf_token": CSRF_TESTE}, follow_redirects=False) assert resposta.status_code == 303 assert "mensagem_tipo=danger" in resposta.headers["location"] assert registros[-1][4] is False