| name | hc-quality-smoke |
| description | Teste de fumaça end-to-end do HC Quality (sistema de CIQ laboratorial em produção). Navega todos os módulos (Hematologia, CIQ-Imuno, Coagulação, Uroanálise, Insumos, Equipamentos, BulaParser, Reports, Admin), executa fluxos críticos com imagens reais de corridas + mocks, e entrega relatório por critério de aceite com evidência em screenshot. Requer Playwright. |
| location | workspace |
HC Quality — Smoke Test End-to-End
Role: QA engineer senior com 10+ anos de experiência em apps React/Firebase.
Missão: validar que o HC Quality em produção não quebrou após a última rodada de mudanças (Ondas 1-5 de correção + anexo operacional do email diário).
Princípio: cada asserção tem evidência. Nada se "assume". Se um fluxo depende de IA (OCR), valida apenas que a chamada foi feita e que uma resposta chegou — não valores exatos.
0. Configuração (o usuário preenche antes de rodar)
BASE_URL = https://hmatologia2.web.app
TEST_USER_EMAIL = [preencha — conta já cadastrada no lab de teste]
TEST_USER_PASSWORD = [preencha]
TEST_LAB_NAME = [preencha — ex: "LabClin Rio Pomba MG"]
WHATSAPP_IMAGES_DIR = [preencha — ex: C:\Users\labcl\Downloads\WhatsApp\2026-04-18]
OUTPUT_DIR = ./smoke-results/$(date +%Y-%m-%d_%H-%M)
Importante: durante o período de testes, o CTO pode ter rodado grantTemporarySuperAdminToAll. Nesse caso qualquer user cadastrado é SuperAdmin — simplifica o teste (você vê menus extras). Se a tela tiver o badge "Super Admin" no canto, está na conta certa.
1. Pré-requisitos e ambiente
-
Instale o browser driver:
npx playwright install chromium
-
Crie o diretório de output:
mkdir -p "$OUTPUT_DIR/screenshots" "$OUTPUT_DIR/videos"
-
Abra o Chromium em modo NÃO-headless na primeira execução pra confirmar visualmente que o app carrega. Nas próximas pode ser headless.
-
Regra de ouro: nunca delete nenhum registro criado pelo teste. Deixa pra limpeza manual do CTO. Você só CRIA com prefix SMOKE_ no nome pra facilitar filtragem depois.
2. Estrutura do relatório de saída
Ao final, grava $OUTPUT_DIR/REPORT.md com:
# Smoke Test HC Quality — {data}
## Sumário
- Total de fluxos: N
- Passou: X
- Falhou: Y
- Bloqueado (dependência externa): Z
## Resultado por fluxo
### ✅ [F01] Login e seleção de lab
- Duração: 3.2s
- Evidência: screenshots/f01-ready.png
- Assertions: 4/4
### ❌ [F05] CIQ-Imuno — registrar run com strip
- Duração: 8.1s
- Falha: botão "Confirmar" não ficou habilitado após upload
- Evidência: screenshots/f05-fail.png
- Stack: ...
[...]
## Detalhes por módulo
[logs + screenshots]
3. Fluxos de teste (ordenados por criticidade)
F01 — Login e seleção de lab (BLOQUEADOR — se falhar, aborta tudo)
Steps:
page.goto(BASE_URL) — espera document ready
- Screenshot:
f01-01-landing.png
- Se aparecer LoginScreen:
- Preenche input com label "E-mail" →
TEST_USER_EMAIL
- Preenche input com label "Senha" →
TEST_USER_PASSWORD
- Clica botão com texto "Entrar"
- Espera até um dos estados:
- EmailVerificationScreen (fail — mandar email)
- FirstLabSetupScreen (fail — user sem lab)
- PendingLabAccessScreen (fail — access pending)
- LabSelectorScreen (clica no lab
TEST_LAB_NAME)
- ModuleHub (ready ✅)
- Screenshot:
f01-02-ready.png
Assertions:
Se falhar: aborta tudo com REPORT.md só com F01. Sem login não tem smoke.
F02 — Navegação ampla (sanity check de roteamento)
Steps:
- No ModuleHub, itera pelas views e clica em cada uma, tira screenshot, volta pro hub.
- Views a visitar (clica no botão com o texto exato):
- "Hematologia" →
f02-01-hematologia.png
- "Coagulação" →
f02-02-coagulacao.png
- "Uroanálise" →
f02-03-uroanalise.png
- "CIQ-Imuno" →
f02-04-ciq-imuno.png
- "Importar bula PDF" →
f02-05-bulaparser.png
- "Relatórios" →
f02-06-reports.png
- "Insumos" →
f02-07-insumos.png
- "Configurações" →
f02-08-settings.png (pode não aparecer se não for admin/owner)
- "Super Admin" / "Painel Super Admin" →
f02-09-superadmin.png (só SuperAdmin)
Assertions por view:
Reporte: lista das views que abriram OK e quais falharam.
F03 — Hematologia: registrar corrida via OCR (USA SUAS IMAGENS)
Setup:
- Clica "Hematologia" na Hub.
- Se dropdown LotSwitcher mostrar "Selecione um lote", escolhe qualquer lote existente. Se nenhum existir → marca fluxo como BLOQUEADO com nota "nenhum lote cadastrado pra testar run".
Steps (usa imagem real do WhatsApp):
- Clica botão "Nova Corrida" (ou "Registrar corrida" / "+ Corrida" — qualquer variante visível)
- Screenshot:
f03-01-form.png
- Upload: pega a primeira imagem de
$WHATSAPP_IMAGES_DIR/*.jpg|*.jpeg|*.png — deve ser um screen do Yumizen H550
- Espera o toast "Processando imagem…" ou equivalente aparecer e sumir (timeout 60s)
- Screenshot:
f03-02-extracted.png — deve mostrar os 17 analitos preenchidos (RBC, HGB, HCT, MCV, MCH, MCHC, RDW, PLT, MPV, PDW, PCT, WBC, NEU#, LYM#, MON#, EOS#, BAS#)
- NÃO clica "Confirmar" (pra não poluir os dados reais). Clica "Cancelar" ou fecha o modal.
Assertions:
Se todas imagens WhatsApp falharem: marca como FAIL (OCR quebrado) e inclui stack do console. Se apenas algumas falharem (ex: imagens borradas): marca como PASSOU com warning.
F04 — Hematologia: visualizar Levey-Jennings e Westgard
Steps:
- Na view Hematologia, toggle "Gráfico" se estiver escondido.
- Seleciona um analito com mais de 5 corridas históricas (ex: "HGB").
- Screenshot:
f04-01-lj-chart.png
- Alterna entre "Fabricante" e "Interna" nas estatísticas (toggle visível).
- Screenshot:
f04-02-stats-toggle.png
Assertions:
F05 — CIQ-Imuno: registrar corrida com strip mockado
Mock: como você não tem foto real de strip de imunoensaio, gera uma imagem sintética antes de rodar:
Se não tiver como gerar sintético, usa a mesma imagem do WhatsApp (o OCR do strip vai falhar ou retornar low confidence — é esperado, apenas valida o pipeline de upload+chamada).
Steps:
- Hub → "CIQ-Imuno"
- Seleciona um lote existente (se não houver, BLOQUEADO)
- Clica "Nova Corrida"
- Seleciona tipo de teste: "HIV" (dropdown)
- Upload da imagem mock
- Espera resposta do OCR (timeout 30s)
- Screenshot:
f05-01-imuno-result.png
- Clica "Cancelar" — não confirma
Assertions:
F06 — Uroanálise: OCR de tira
Mesma lógica de F05 — usa mock ou reaproveita uma imagem do WhatsApp.
Steps:
- Hub → "Uroanálise"
- Seleciona lote existente (se não houver, BLOQUEADO)
- "Nova Corrida" → upload da imagem
- Espera OCR. Screenshot:
f06-01-uro-result.png
- Cancelar.
Assertions:
F07 — Coagulação: visualização (read-only)
Steps:
- Hub → "Coagulação"
- Screenshot da view inteira.
- Se houver lote cadastrado: abre, lista corridas, fecha.
- Se tiver botão "FR-10" / "Gerar relatório regulatório": clica e verifica se abre modal (mas NÃO confirma geração).
Assertions:
F08 — Insumos: criar produto mock + lote mock
Cuidado: esse fluxo CRIA dados. Prefix tudo com SMOKE_ pra o CTO limpar depois.
Steps:
-
Hub → "Insumos" → aba "Produtos"
-
Clica "Novo Produto" (ou "+ Produto")
-
Preenche:
- Módulo: "hematologia"
- Tipo: "controle"
- Fabricante:
SMOKE_Bio-Rad
- Nome Comercial:
SMOKE_Multiqual Test
- Equipamentos Compatíveis: seleciona qualquer um
- Estabilidade Default: 30 dias
- Nível Default: 2
-
Salva. Screenshot: f08-01-produto-ok.png
-
Espera toast de sucesso.
-
Verifica que o produto aparece na lista com o prefix SMOKE_.
-
Aba "Lotes" → "+ Lote"
-
Preenche:
- Produto: seleciona o
SMOKE_Multiqual Test criado
- Lote:
SMOKE-LOT-${timestamp}
- Data Vencimento: +180 dias a partir de hoje
-
Salva. Screenshot: f08-02-lote-ok.png
Assertions:
F09 — Insumos: movimentação (abertura) — testa chain hash
Steps:
- No lote
SMOKE-LOT-* criado em F08, clica "Abrir frasco" (ou "Movimentação → Abertura")
- Preenche motivo se pedido. Confirma.
- Screenshot:
f09-01-movimentacao.png
- Aguarda 3s — Cloud Function
onInsumoMovimentacaoCreate deve selar o doc assincronamente.
- Abre timeline do lote. Verifica aparecer um evento de "Abertura".
Assertions:
F10 — BulaParser: upload PDF mock
Mock: usa qualquer PDF pequeno que tenha no sistema (pode ser o próprio README do projeto exportado pra PDF, ou um PDF de 1 página criado com:
echo "BULA MOCK — Controle Hematologia SMOKE TEST" > mock.txt
Se não tiver pandoc/chrome-headless pra gerar PDF: marca como BLOQUEADO com nota.
Steps:
- Hub → "Importar bula PDF"
- Upload do PDF mock
- Espera resposta do Gemini (timeout 60s)
- Screenshot:
f10-01-bula-result.png
Assertions:
F11 — Relatórios: visualização + filtro
Steps:
- Hub → "Relatórios"
- Aplica filtro: últimos 30 dias, todos módulos, todos status.
- Screenshot:
f11-01-reports.png
- Clica "Exportar CSV" ou equivalente — captura o download e verifica que é um arquivo não-vazio.
- NÃO clica "Enviar por email" (evita disparar Resend).
Assertions:
F12 — Configurações do lab (Lab-Settings)
Requer: role=admin ou owner ou SuperAdmin. Se o usuário de teste não tem essa role, marca como SKIP.
Steps:
- Hub → "Configurações"
- Screenshot:
f12-01-settings.png
- Toggle uma regra Westgard (ex: "1-2s") — se estiver desligada, liga; se ligada, deixa como estava.
- Clica "Salvar" (só se fez mudança).
- Verifica toast de sucesso.
- Se mudou algo, DESFAZ antes de sair.
Assertions:
F13 — Admin / SuperAdmin: users + migrations
Requer: SuperAdmin (durante período de testes, todos devem ser — vide grant).
Steps:
- Menu de conta (canto superior direito) → "Painel Super Admin" ou Hub → "Super Admin"
- Aba "Usuários"
- Screenshot:
f13-01-users-list.png
- Verifica que a lista carrega pelo menos o próprio usuário.
- Aba "Migrations"
- Screenshot:
f13-02-migrations.png
- NÃO clica "Aplicar" em nenhuma migration. Só clica em "Dry-run" das migrations que têm dry-run disponível:
- "Dry-run (inspeciona diff)" em "Provisioning de claims" — deve retornar
updated: 0 se claims já provisionadas
- "Dry-run grant" em "SuperAdmin temporário" — retorna lista sem aplicar
- Screenshot dos resultados.
Assertions:
F14 — Email diário: backup + operacional (verifica existência, NÃO dispara)
Não dispara o envio — só valida que as configurações estão acessíveis.
Steps:
- Configurações → seção "Backup Diário"
- Screenshot:
f14-01-backup-settings.png
- Verifica campos:
- "Backup habilitado": toggle visível
- "Emails destinatários": input com pelo menos 1 email
- "Threshold de inatividade": input numérico
- Verifica campo informativo "Relatório Operacional (2º anexo)" ou "Anexo operacional" — deve mencionar o novo PDF.
Assertions:
4. Fluxos negativos (expectativas de falha controlada)
N01 — Login com senha errada
- Preenche senha errada proposital
- Espera: toast de erro com mensagem amigável
- Não espera: crash, página branca, erro 500 visível
N02 — Upload de arquivo inválido (OCR)
- Upload de um .txt renomeado pra .jpg no campo de run
- Espera: erro controlado ("formato inválido" ou "não foi possível ler a imagem")
- Não espera: crash do frontend
N03 — Formulário com campos obrigatórios vazios
- Abre "Novo Produto", clica "Salvar" sem preencher nada
- Espera: validação inline bloqueia o submit
- Não espera: request ao servidor
5. Políticas gerais
Não pode
- Deletar QUALQUER dado existente
- Confirmar ("Salvar" / "Confirmar" / "Enviar") operações em dados reais — só em dados criados pelo próprio teste com prefix
SMOKE_
- Chamar
grantTemporarySuperAdminToAll, revokeTemporarySuperAdmin, provisionModulesClaims, deleteUser, removeUserFromLab — essas são destrutivas
- Disparar
triggerCQIReport, triggerLabBackup, triggerFirestoreExport — enviam email/consomem quota
- Testar em mais de um lab simultaneamente
Deve
- Tirar screenshot ANTES e DEPOIS de cada ação destrutiva/criativa
- Capturar console logs e errors (
page.on('console'), page.on('pageerror'))
- Capturar network requests falhos (
response.status() >= 400)
- Gerar
REPORT.md completo ao final, mesmo se falhar no meio
- Fazer
page.waitForLoadState('networkidle') entre navegações
Boas práticas
- Antes de cada fluxo, reset: fecha modais abertos, volta pro Hub via menu
- Timeout global: 60s por ação (OCR pode demorar)
- Retry: 2x em falhas de rede (ECONNRESET, 503)
- Captura HAR (
await page.context().tracing.start(...)) pra fluxos que falharem
6. Resumo de cobertura esperada
| Módulo | F# | Criticidade | OCR? | Cria dados? |
|---|
| Auth | F01 | Bloqueador | — | — |
| Navegação | F02 | Alta | — | — |
| Hematologia | F03, F04 | Alta | ✅ Gemini | Não (cancela) |
| CIQ-Imuno | F05 | Alta | ✅ Gemini | Não |
| Uroanálise | F06 | Média | ✅ Gemini | Não |
| Coagulação | F07 | Média | — | — |
| Insumos | F08, F09 | Alta | — | ✅ (SMOKE_*) |
| BulaParser | F10 | Média | ✅ Gemini | Não |
| Reports | F11 | Média | — | — |
| Settings | F12 | Baixa | — | Toggle revertido |
| Admin | F13 | Média | — | Só dry-runs |
| Backup config | F14 | Baixa | — | — |
| Negativos | N01-N03 | Média | — | — |
Critério de passa global: F01 + F02 + F03 + F05 + F06 + F08 + F13 passam → smoke OK.
Se qualquer um dos bloqueadores falhar → smoke FAIL e merge do app deve ser revertido.
7. Entrega
Ao terminar:
$OUTPUT_DIR/REPORT.md com sumário executivo
$OUTPUT_DIR/screenshots/*.png organizados por fluxo
$OUTPUT_DIR/console.log com logs agregados do browser
$OUTPUT_DIR/network-failures.json com requests que retornaram >= 400
- Exit code: 0 se tudo passou; 1 se 1+ bloqueador falhou; 2 se erros em fluxos não-bloqueadores
Se exit != 0, imprime no terminal:
❌ SMOKE FAIL
bloqueadores falhos: F01, F03
Relatório completo: $OUTPUT_DIR/REPORT.md