# Bateria de testes — Reem Notas (ambiente de teste)

Roteiro de regressão para ser executado por um agente (inclusive modelos menores)
com a skill `agent-browser`. Não é preciso conhecer o projeto: siga os casos na
ordem e preencha o relatório do final.

## Regras de segurança (leia antes de tudo)

1. **Somente leitura + interações seguras.** É PROIBIDO:
   - clicar em qualquer botão que abra confirmação (`Tem certeza?`, `Rebuscar o
     plano?` etc.) — se a confirmação abrir por engano, cancele;
   - finalizar, arquivar, excluir ou registrar pagamento de consolidação;
   - criar, editar ou excluir usuários, perfis, contatos, grupos ou eventos;
   - qualquer envio de WhatsApp/notificação.
   - Formulários só podem ser preenchidos nos casos em que o roteiro mandar
     explicitamente (login e campos de busca).
2. **Ambiente**: `https://teste.reemtransportes.com.br` (nunca o domínio de
   produção).
3. **Avisos do ambiente de teste** (não são falhas):
   - Não há pagamentos registrados (`pago_em` vazio) — gráficos e tabelas de
     pagamento vazios são o esperado;
   - O deploy é manual: o site pode estar atrás do código do repositório. Se um
     caso falhar por algo que parece "código novo que não chegou lá", registre
     como `DEPLOY?` em vez de `FALHOU`.
4. Screenshots de evidência vão para o diretório de scratchpad da sessão.

## Credenciais

- **Admin (web)**: e-mail `admin@reem.com`, senha `Reem@2026!` — em
  `https://teste.reemtransportes.com.br/auth/login`, aba "E-mail".
- **Motorista**: aba "PIN Motorista" da mesma tela (PIN de 4 dígitos; se nenhum
  PIN de teste for fornecido na tarefa, marque o caso 8 como `PULADO`).

## Teste 0 — transversal (rodar em TODA página visitada)

Depois de abrir cada página do roteiro, sempre rode:

```bash
agent-browser errors                      # deve vir vazio
agent-browser network requests | grep -E " (4[0-9]{2}|5[0-9]{2})$"   # deve vir vazio
```

- Qualquer erro de console JS ⇒ FALHOU (anote a mensagem).
- Qualquer request com status ≥ 400 ⇒ FALHOU (anote a URL — um asset
  `*_controller-*.js` com 404 significa Stimulus quebrado na página inteira; foi
  exatamente assim que o bug do preview do romaneio passou despercebido).

⚠️ **404 de asset engana duas vezes.** O Cloudflare guarda os arquivos por um ano,
então uma tela pode parecer boa enquanto a origem já não serve nada — sempre
confira com cache-buster:

```bash
curl -s -o /dev/null -w "%{http_code}\n" "https://teste.reemtransportes.com.br/assets/controllers/<arquivo>.js?cb=$RANDOM"
```

E se **todos** derem 404, o problema é o build inteiro, não os arquivos: a tarefa
`tailwindcss:build` aborta o `assets:precompile` quando falta
`app/assets/tailwind/application.css`. O Propshaft, sem manifesto, continua
gerando URLs com o digest certo — por isso a página abre normal e o JS some em
silêncio. Confira no servidor com
`docker compose logs app | grep '\[boot\] assets'`.
- Exceção: chamadas para domínios de terceiros (cloudflareinsights etc.) com
  falha não reprovam o caso; registre como observação.

## Roteiro

### Caso 1 — Login por e-mail

```bash
agent-browser open https://teste.reemtransportes.com.br/auth/login
agent-browser snapshot -i          # localizar refs de E-mail, Senha e Entrar
agent-browser fill @eX "admin@reem.com"
agent-browser fill @eY "Reem@2026!"
agent-browser press Enter
agent-browser wait --load networkidle
agent-browser get url
```

**PASSOU se**: a URL final é `/dashboard` (ou a home do perfil) e o Teste 0 passa.
Obs.: use `press Enter` — o clique no botão às vezes não navega no primeiro clique.

### Caso 2 — Dashboards

```bash
agent-browser open https://teste.reemtransportes.com.br/dashboard
agent-browser eval "document.querySelectorAll('canvas').length"      # gráficos Chart.js
agent-browser eval "document.documentElement.scrollWidth <= window.innerWidth"  # sem overflow horizontal
agent-browser screenshot dashboard.png
agent-browser open https://teste.reemtransportes.com.br/dashboard/operacoes
# repetir os três comandos acima (operacoes.png)
```

**PASSOU se**: as duas páginas carregam, há pelo menos 1 `canvas` em cada, sem
overflow horizontal, Teste 0 limpo.

**Versão mobile** (obrigatória no dashboard):

```bash
agent-browser set device "iPhone 16"
agent-browser open https://teste.reemtransportes.com.br/dashboard
agent-browser eval "document.documentElement.scrollWidth <= window.innerWidth"
agent-browser screenshot dashboard-mobile.png
agent-browser set viewport 1280 800   # voltar ao desktop
```

**PASSOU se**: sem scroll horizontal no mobile (regra do projeto: nada de tabela
que exija zoom).

### Caso 3 — Consolidações (abas e filtros)

```bash
agent-browser open "https://teste.reemtransportes.com.br/consolidacoes?visao=lista"
agent-browser snapshot -i | head -40
agent-browser open "https://teste.reemtransportes.com.br/consolidacoes?visao=motoristas"
agent-browser get url
```

**PASSOU se**: as duas visões abrem sem erro; ao trocar de visão os filtros da URL
se mantêm (as visões são abas da MESMA tela, não telas separadas); Teste 0 limpo.

### Caso 4 — Romaneios (inclui o preview)

```bash
agent-browser open https://teste.reemtransportes.com.br/admin/romaneios
agent-browser snapshot -i | head -30          # lista de romaneios
# abrir o primeiro romaneio da lista (link do item):
agent-browser click @eX
agent-browser wait --load networkidle
```

Na tela do romaneio:

A prévia é um pop-up cujo estado mora na **URL** (`?previa=1`) — abre, fecha e
troca de folha por navegação normal, sem JavaScript. **Teste sempre navegando de
verdade**, nunca com `.click()` de dentro do `eval`: o clique programático já
mascarou um bug (com o Turbo carregado, o mecanismo anterior por `#hash` não
abria, mas o `.click()` fazia parecer que abria).

```bash
# 4a. Fechada, o pop-up NÃO existe no HTML (e nenhum PDF é gerado):
agent-browser open "https://teste.reemtransportes.com.br/admin/romaneios/13"
agent-browser eval "document.querySelector('[data-romaneio-target=overlay]') ? 'PRESENTE (erro)' : 'ausente (correto)'"

# 4b. Abrir pelo botão, com clique REAL:
agent-browser snapshot -i | grep -i "prévia"     # pegar o ref do link
agent-browser click @eN
agent-browser eval "(()=>{const o=document.querySelector('[data-romaneio-target=overlay]'); if(!o) return 'NAO ABRIU'; const c=[...o.querySelectorAll('span')].find(s=>s.textContent.includes(' de ')); return 'aberto | '+c.textContent.trim()+' | url='+location.search;})()"
# esperado: "aberto | 1 de 72 · GADE_001 | url=?veiculo=GADE_001&previa=1"

# 4c. Avançar de folha SEM fechar (é o carrossel):
agent-browser eval "(()=>{const o=document.querySelector('[data-romaneio-target=overlay]'); const a=[...o.querySelectorAll('a')].filter(x=>(x.getAttribute('href')||'').includes('previa')); return a.at(-1).getAttribute('href');})()"
# copie o href e navegue nele com `agent-browser open`; o pop-up tem que continuar
# aberto e o contador virar "2 de 72".

# 4d. Fechar pelo ✕ (volta para a URL sem previa) e o pop-up sumir do HTML.

# 4e. O PDF responde e é PDF de verdade (não a página de login):
agent-browser eval "(async()=>{const r=await fetch('/admin/romaneios/13/pdf?veiculo=GADE_001&cb='+Math.random()); const b=await r.blob(); return r.status+' '+b.type+' '+Math.round(b.size/1024)+'KB';})()"
# esperado: "200 application/pdf <N>KB"
```

**PASSOU se**: 4a ausente, 4b abre com o contador certo, 4c avança mantendo
aberto, 4d fecha, 4e devolve `application/pdf`. **NÃO** clicar em "Reimportar
plano" (tem confirmação).

⚠️ Se 4e devolver `text/html`, a sessão caiu no meio do teste — refaça o login e
repita, **não** registre como falha do PDF (já deu falso positivo assim).

### Caso 4f — Prévia em branco é o NAVEGADOR, não o sistema

O quadro do PDF pode aparecer branco mesmo com tudo funcionando, porque o
navegador se recusa a desenhar PDF em iframe. As três causas conhecidas:

1. **"Baixar PDFs em vez de abri-los"** ligado (Chrome/Brave/Edge:
   `chrome://settings/content/pdfDocuments`);
2. **bloqueador de conteúdo** (Brave Shields, uBlock) barrando o quadro;
3. **bloqueio de pop-up/redirecionamento** do navegador.

O sistema **não consegue detectar isso** (o iframe é opaco por segurança), por
isso o pop-up traz um aviso fixo com a saída ("abra em outra aba"). Antes de
abrir bug de "prévia não aparece", confirme que **não** é o navegador:

```bash
# Se ISTO devolve application/pdf, o servidor está certo e o problema é o navegador:
agent-browser eval "(async()=>{const r=await fetch('/admin/romaneios/13/pdf?veiculo=GADE_001&cb='+Math.random()); const b=await r.blob(); return r.status+' '+b.type;})()"
```

**PASSOU se**: o aviso está visível no rodapé do pop-up e o `fetch` acima devolve
`application/pdf`. Se o fetch devolve PDF e o quadro está branco, o veredito é
**"configuração do navegador"**, não falha do sistema — registre assim.

### Caso 4e — Vínculo manual da operação (só leitura)

O bloco "Operação do mês" tem que aparecer em todo romaneio, e o formulário
precisa funcionar **sem JavaScript** (é `<details>` nativo + form comum):

```bash
agent-browser eval "(()=>{const d=[...document.querySelectorAll('details')].find(x=>x.querySelector('select[name=operacao_tabela]')); return d ? 'existe | aberto:'+d.open+' | opcoes:'+d.querySelectorAll('option').length : 'AUSENTE';})()"
```

⚠️ Procure pelo `select[name=operacao_tabela]`, **não** pelo texto "Operação do
mês": esse rótulo fica FORA do `<details>` e é renderizado em maiúsculas pelo
CSS, então busca por texto dá falso negativo (já aconteceu num diagnóstico).

**PASSOU se**: o bloco existe; num romaneio **sem** operação ele vem `aberto:true`
(a pendência fica à vista) e num **com** operação vem `aberto:false`; a lista tem
mais de uma `option`.
⚠️ **NÃO enviar o formulário** — vincular altera dados do romaneio. Só conferir
que o controle está lá e abre.

### Caso 5 — Planilha SimpliRoute

```bash
agent-browser open https://teste.reemtransportes.com.br/admin/planilha_simpli_route
agent-browser snapshot -i | head -20
```

**PASSOU se**: a tela abre com a lista de operações disponíveis, Teste 0 limpo.
(Não é preciso baixar o arquivo.)

### Caso 6 — Telas de admin

Abrir cada URL e rodar o Teste 0:

```
/admin/usuarios
/admin/perfis
/admin/configuracoes
/admin/auditoria_logs
/admin/edicao_lancamento
```

**PASSOU se**: todas abrem com conteúdo (título + tabela/cards), sem erro.
**NÃO** editar nada nessas telas.

### Caso 7 — Notificações

Abrir cada URL e rodar o Teste 0:

```
/admin/contatos
/admin/grupos
/admin/eventos
/admin/envios
```

**PASSOU se**: todas abrem, sem erro. **NÃO** disparar envio nem mexer no
WhatsApp/sessão.

### Caso 8 — Login PIN do motorista (mobile)

Somente se um PIN de teste foi fornecido na tarefa; senão marcar `PULADO`.

```bash
agent-browser set device "iPhone 16"
agent-browser open https://teste.reemtransportes.com.br/auth/login
# clicar na aba "PIN Motorista", digitar o PIN, entrar
```

**PASSOU se**: cai no dashboard do motorista, valores legíveis sem zoom,
Teste 0 limpo. Ao final: `agent-browser set viewport 1280 800`.

## Caso 9 — Tempo de resposta (performance)

Mede o tempo real de cada tela e do PDF. Rode logado, com a rede parada (sem
outra aba baixando coisa), e compare com a linha de base.

```bash
# Tempo das telas (TTFB | resposta completa | DOM pronto)
for u in /dashboard /dashboard/operacoes "/consolidacoes?visao=lista" /admin/romaneios /admin/romaneios/13; do
  agent-browser open "https://teste.reemtransportes.com.br$u" >/dev/null
  agent-browser eval "(()=>{const n=performance.getEntriesByType('navigation')[0]; return Math.round(n.responseStart-n.requestStart)+'|'+Math.round(n.responseEnd-n.requestStart)+'|'+Math.round(n.domContentLoadedEventEnd-n.startTime);})()"
done
```

```bash
# Tempo do PDF (o mais pesado do sistema). Com cache-buster, senão mede o cache.
agent-browser eval "(async()=>{const t0=performance.now(); const r=await fetch('/admin/romaneios/13/pdf?veiculo=GADE_002&cb='+Math.random()); const b=await r.blob(); return Math.round(performance.now()-t0)+'ms, '+Math.round(b.size/1024)+' KB';})()"
```

**Linha de base medida em 28/08/2026** (romaneio de 2.047 paradas / 72 veículos,
ambiente de teste, acesso pelo domínio com Cloudflare na frente):

| Alvo | TTFB | Resposta | DOM pronto |
|---|---|---|---|
| `/dashboard` | 339 ms | 340 ms | 493 ms |
| `/dashboard/operacoes` | 168 ms | 251 ms | 402 ms |
| `/consolidacoes?visao=lista` | 349 ms | 351 ms | 430 ms |
| `/admin/romaneios` | 49 ms | 50 ms | 127 ms |
| `/admin/romaneios/13` | 71 ms | 78 ms | 155 ms |
| **PDF de 1 veículo** | — | **228 ms** (84 KB) | — |
| **PDF de TODOS (72)** | — | **8.947 ms** (1,7 MB) | — |

**Orçamento — FALHOU se passar de**: 1 s de TTFB em qualquer tela; 1 s no PDF de
um veículo (é ele que a prévia carrega, tem que abrir na hora); 30 s no PDF
completo (acima disso o proxy corta a conexão e o operador recebe erro).

⚠️ **Ponto de atenção conhecido**: o PDF de todos os veículos leva ~9 s e segura
um processo do servidor esse tempo todo. Ainda dentro do aceitável para uma ação
manual e pontual, mas é o primeiro candidato a virar download em segundo plano se
o volume crescer ou se dois operadores baixarem ao mesmo tempo. **Não** compare
esse número com o do PDF de um veículo: são unidades diferentes (1 folha × 72).

## Caso 10 — Mobile: quebras visuais (varredura)

Roda em **todas** as telas do roteiro com `agent-browser set device "iPhone 16"`
(393×852), logado. São três medições objetivas; anote o número, não só passou/falhou.

### 10a — Rolagem horizontal

Nenhuma tela pode ter rolagem lateral no celular (diretriz 3: nada que exija zoom).

```bash
agent-browser set device "iPhone 16"
for u in /dashboard /dashboard/operacoes "/consolidacoes?visao=lista" "/consolidacoes?visao=motoristas" /admin/romaneios /admin/romaneios/13; do
  agent-browser open "https://teste.reemtransportes.com.br$u" >/dev/null
  agent-browser eval "document.documentElement.scrollWidth+'/'+document.documentElement.clientWidth"
done
```

**PASSOU se**: os dois números são iguais (ex.: `393/393`) em todas.
Para achar o culpado quando falhar:

```bash
agent-browser eval "(()=>{const vw=document.documentElement.clientWidth; return [...document.querySelectorAll('*')].filter(e=>{const b=e.getBoundingClientRect(); return b.right>vw+2 && b.width>40 && getComputedStyle(e).position!=='fixed';}).slice(0,5).map(e=>e.tagName+'.'+String(e.className).split(' ').slice(0,2).join('.')+' right='+Math.round(e.getBoundingClientRect().right)).join(' || ');})()"
```

> ⚠️ Causa recorrente: contêiner `flex` **sem `flex-wrap`** com botões que não cabem,
> ou `<input class="flex-1">` **sem `min-w-0`** (input não encolhe abaixo da largura
> intrínseca). Foram as duas causas de 28/08/2026.

### 10b — Menu inteiro alcançável

Todo item do menu tem que ser alcançável rolando — inclusive o **Sair**, o último.

```bash
agent-browser open "https://teste.reemtransportes.com.br/dashboard"
agent-browser snapshot -i | grep -i "menu"      # pegar o ref do botão "Abrir menu"
agent-browser click @eN
agent-browser eval "(()=>{const nav=document.querySelector('#sidebar nav'); if(!nav) return 'NAV AUSENTE'; const ult=[...document.querySelectorAll('#sidebar a')].at(-1); return 'nav rola='+(nav.scrollHeight>nav.clientHeight)+' overflowY='+getComputedStyle(nav).overflowY+' | ultimo item: '+ult.textContent.trim()+' | fora da tela por '+Math.max(0, Math.round(ult.getBoundingClientRect().bottom-window.innerHeight))+'px';})()"
```

**PASSOU se**: `overflowY=auto` e "fora da tela por 0px" (o item pode estar abaixo
da dobra, desde que o `<nav>` role até ele).
**FALHOU se**: `overflowY=visible` ou o último item aparece fora por N px — foi o
bug de 28/08/2026, em que 7 itens (incluindo Sair) eram inalcançáveis no celular.

> O que segura isso é o `flex flex-col` no `<aside id="sidebar">`: sem ele o
> `flex-1 overflow-y-auto` do `<nav>` não tem efeito nenhum.

### 10c — Alvos de toque

```bash
agent-browser eval "(()=>{const p=[...document.querySelectorAll('a,button,input,select,summary')].filter(e=>{const b=e.getBoundingClientRect(); return b.height>0 && b.height<44;}); return p.length+' alvos <44px';})()"
```

**Linha de base após as correções de 28/08/2026** (iPhone 16): dashboard tinha
**63** antes do ajuste da paginação; as demais telas ficam entre 3 e 5. Um número
que **cresce** entre execuções é regressão — vale investigar o que foi
adicionado, não apenas registrar.

## Relatório final (obrigatório)

Terminar a execução com uma tabela e a lista de falhas:

| Caso | Resultado | Evidência |
|------|-----------|-----------|
| 0 (por página) | PASSOU/FALHOU | página + erro |
| 1 Login | PASSOU/FALHOU/DEPLOY?/PULADO | screenshot |
| 2 Dashboards | … | … |
| 3 Consolidações | … | … |
| 4 Romaneios/preview | … | … |
| 5 Planilha | … | … |
| 6 Admin | … | … |
| 7 Notificações | … | … |
| 8 PIN motorista | … | … |
| 9 Performance | … | tabela de tempos |
| 10 Mobile (10a/b/c) | … | larguras, menu, alvos |

Depois da tabela, listar **somente as falhas**, cada uma com: URL, o que era
esperado, o que aconteceu (mensagem de erro/console) e o caminho do screenshot.
Se tudo passou, dizer isso em uma linha. Encerrar com `agent-browser close`.
