#!/usr/bin/env python3 """ teste_e2e.py — o fluxo inteiro, do upload ao download, sem servidor rodando. Usa o test client do Flask: exercita exatamente as rotas de app/servidor.py, sem porta aberta e sem depender de o servidor estar de pé. O que esta suíte existe para provar, na ordem: 1. upload NUNCA baixa nada — o download só sai do /exportar, depois de um clique, e só quando o exportador não tem pendência; 2. SD com pendência é recusada no servidor mesmo por POST direto, e a tela mostra formulário SÓ com os campos pendentes; 3. a correção feita no formulário chega ao JSON — e o JSON é byte-idêntico ao do exporta_sd.py na linha de comando sobre um SD.md com a mesma correção; 4. campo não pendente não é tocado por um Salvar (o formulário só manda o que está pendente, e o servidor só toca no que vem). Roda assim: python3 scripts/teste_e2e.py 0 = tudo passou; 1 = alguma checagem falhou """ from __future__ import annotations import html as H import json import re import subprocess import sys import tempfile from io import BytesIO from pathlib import Path RAIZ = Path(__file__).resolve().parent.parent sys.path.insert(0, str(RAIZ / "scripts")) sys.path.insert(0, str(RAIZ / "app")) from caminhos import PROJETOS # noqa: E402 from regras_sd import ler_sd_texto, secao # noqa: E402 import servidor # noqa: E402 FALHAS: list[str] = [] CLIENTE = servidor.app.test_client() SD8 = PROJETOS / "P2-vacinacao/sds/SD8-mvp-vacina-em-dia/SD.md" SD10 = PROJETOS / "P2-vacinacao/sds/SD10-crie/SD.md" SD20 = PROJETOS / "P4-cancer-de-mama/sds/SD20-siscan-d1/SD.md" SD24 = PROJETOS / "P5-portal-rmds/sds/SD24-mvp-institucional/SD.md" SD31 = PROJETOS / "P7-assistencia-farmaceutica/sds/SD31-fundacao-da-base-de-dispensacao/SD.md" def ck(cond, desc): print(f" {'ok ' if cond else 'FALHA'} {desc}") if not cond: FALHAS.append(desc) def post(rota, dados=None, **kw): return CLIENTE.post(rota, data=dados or {}, follow_redirects=True, **kw) def texto(resp): return resp.get_data(as_text=True) def enviar(caminho: Path, nome: str | None = None, conteudo: bytes | None = None): dados = {"arquivo": (BytesIO(conteudo if conteudo is not None else caminho.read_bytes()), nome or caminho.name)} return post("/upload", dados, content_type="multipart/form-data") def pagina(): return texto(CLIENTE.get("/revisar", follow_redirects=True)) def reiniciar(): post("/reiniciar") def campos_do_form(pag: str) -> dict: """Relê o formulário de pendências como o navegador o reenviaria.""" campos = {} for m in re.finditer(r']*name="([^"]+)"[^>]*>', pag): tag = m.group(0) if any(t in tag for t in ('type="radio"', 'type="checkbox"', 'type="file"')): continue v = re.search(r'value="([^"]*)"', tag) campos[m.group(1)] = H.unescape(v.group(1)) if v else "" for m in re.finditer(r']*name="([^"]+)"[^>]*>(.*?)', pag, re.S): campos[m.group(1)] = H.unescape(m.group(2)) for m in re.finditer(r']*name="([^"]+)"[^>]*>(.*?)', pag, re.S): sel = re.search(r'