Files
GTI_GERENCIADOR_FISCAL/tests/test_router_contatos.py
T
Gustavo bb8fd596b1 feat: protecao CSRF (double-submit cookie) e paginacao da lista de clientes
CSRF: novo app/csrf.py + middleware em app/main.py garantem um cookie
csrf_token por navegador; todo formulario que muda estado (criar/editar/
excluir cliente, adicionar/editar/excluir contato) embute esse valor
como campo oculto, e Depends(exigir_csrf) confere no POST que o valor
enviado bate com o cookie antes de deixar a rota executar. Verificado
ponta a ponta com o app real rodando (curl): token errado -> 403,
token correto -> 303.

Paginacao: db_clientes.listar_clientes ganha offset, nova
contar_clientes(); GET /clientes aceita ?pagina=N (100 clientes por
pagina), template mostra Anterior/Proxima e o total.

53/53 testes passando (8 novos).
2026-08-13 11:02:17 -03:00

99 lines
4.4 KiB
Python

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)
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
assert chamadas["dados"] == (1, "Fulano", "75999090001", 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", "75999090002", "fulano@example.com")
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)