# Testes — bipagem-codigo-barras-fator

## Cobertura

| Componente | Tipo | Path | Status |
|---|---|---|---|
| Migration 001_create_produtos_codigos_barras.sql (idempotência) | integration | Rodada via PHP inline | PASS (no-op, 4 índices verificados) |
| ProdutoCodigoBarraSonda::resolverPorCodigo — retorna registro, fator float, isolamento de tenant, código vazio | integration | FatorBipagemIntegrationTest.php (casos 1a–1e) | PASS |
| ProdutoCodigoBarraSonda::listarPorProdutos — agrupamento, float, mapa vazio, lista vazia | integration | FatorBipagemIntegrationTest.php (casos 2a–2h) | PASS |
| Precedência Sonda > campo do produto (resolverPorCodigo estrita) | integration | FatorBipagemIntegrationTest.php (casos 3a–3c) | PASS |
| MissoesBipagem::biparItem — caixa fator=10 em item qtd=10 → delta=10, 1 extrato, payload fator/tipo | integration | FatorBipagemIntegrationTest.php (casos 4a–4g) | PASS |
| MissoesBipagem::biparItem — bloqueio caixa fator=10 em item qtd=7; 7 unitárias completam | integration | FatorBipagemIntegrationTest.php (casos 5a–5c) | PASS |
| MissoesBipagem — pesável KG: 6 bipagens em item pede 5, sem bloqueio | integration | FatorBipagemIntegrationTest.php (casos 6a–6b) | PASS |
| MissoesBipagem — não-regressão: produto sem Sonda soma 1, 1 extrato, payload.fator=1 | integration | FatorBipagemIntegrationTest.php (casos 7a–7d) | PASS |

**Total: 42 asserções PASS / 0 FAIL**

## Gaps de cobertura (e justificativa)

- **Presenters (MissaoPresenter, SeparacaoPresenter, PesagemPresenter)** — não cobertos por teste automatizado. A montagem de `codigosBarras` nos Presenters depende de um render HTML completo com dados reais de missão; o smoke test manual (item 7 da task de frontend) é o vetor adequado. O caminho crítico (query `listarPorProdutos` + agrupamento) está coberto pelo caso 2.
- **execucao_bipagem.php** (1 linha adicionada: `'codigosBarras' => $itemBase['codigosBarras'] ?? []`) — PHP template; coberto implicitamente pelo smoke manual da separação.
- **Frontend JS** (separacao/item.js, carregamento/item.js) — fora do escopo de teste automatizado. O JS usa `node --check` para sintaxe (executado pelo dev frontend) e smoke manual.
- **bipagemLote** — não coberto nesta suíte. A lógica de lote não foi alterada (confirmado pelo 03-backend.md: "sem mudança de lógica no lote"); o `quantidade_delta` já era o fator. Risco baixo; cobriria com um segundo arquivo de integração se necessário.
- **adicionarQuantidade / reduzirQuantidade (botões +/-)** — os wrappers chamam `alterarQuantidade` com delta=±1 fixo. Esse caminho não foi alterado; não-regressão está garantida pelo fato de `alterarQuantidade` receber delta como parâmetro e o fator=1 ser o default natural do delta=1.

## Output da execução

### Migration (idempotência)

```
Banco: dev_gx_goldie
Migration executada sem erros (idempotente OK)
Tabela existente: SIM
Indices esperados: 4/4
```

### Teste de integração

```
====================================================
INTEGRATION — FatorBipagem (dev_gx_goldie)
====================================================

[PASS] Seed: produto sentinela criado (id=16540)
[PASS] Seed: produto sentinela NR criado (id=16541)
[PASS] Seed: produto sentinela KG criado (id=16542)
[PASS] Seed: registro PCB fator=10 criado (id=24)
[PASS] Seed: registro PCB outro tenant criado
[PASS] Seed: missão sentinela criada (id=2704)
[PASS] Seed: item sentinela qtd=10 criado (id=128377)
[PASS] Seed: item sentinela qtd=7 criado (id=128379)
[PASS] Seed: item sentinela KG criado (id=128380)
[PASS] Seed: item sentinela NR criado (id=128381)

--- CASO 1: resolverPorCodigo ---
[PASS] 1a. resolverPorCodigo retorna registro para codigo sentinela
[PASS] 1b. fator=10 no registro retornado
[PASS] 1c. produto_id correto no registro
[PASS] 1d. codigo de outro tenant (block=999778) não resolve com session block=999777 (AC1.5)
[PASS] 1e. codigo vazio retorna null

--- CASO 2: listarPorProdutos ---
[PASS] 2a. listarPorProdutos retorna entrada para produto_id sentinela
[PASS] 2b. lista não vazia para produto sentinela
[PASS] 2c. fator é float (não string)
[PASS] 2d. fator=10.0 (float)
[PASS] 2e. codigo_barras presente
[PASS] 2f. tipo_codigo_barras presente
[PASS] 2g. produto sem Sonda não aparece no mapa
[PASS] 2h. array vazio retorna []

--- CASO 3: Precedência Sonda > campo do produto ---
[PASS] 3a. resolverPorCodigo estrita (com produtoId) encontra registro
[PASS] 3b. fator da tabela = 10.0 (precedência Sonda)
[PASS] 3c. codigo só do campo do produto não está na Sonda → null (fator 1 seria aplicado pelo Satélite)

--- CASO 4: biparItem caixa fator=10 em item qtd=10 ---
[PASS] 4a. biparItem caixa fator=10 em item qtd=10 retorna success
[PASS] 4b. quantidade_bipada = 10 (fator aplicado como delta)
[PASS] 4c. quantidade_bipada_scan = 10
[PASS] 4d. exatamente 1 extrato gravado (1 leitura = 1 log, AC3.1)
[PASS] 4e. payload.delta = 10 (AC3.2)
[PASS] 4f. payload.fator = 10 (AC3.2)
[PASS] 4g. payload.tipo_codigo_barras = DUN

--- CASO 5: bloqueio fator=10 em item qtd=7 ---
[PASS] 5a. biparItem caixa fator=10 em item qtd=7 retorna error (AC4.1)
[PASS] 5b. quantidade_bipada permanece 0 após bloqueio (AC4.1)
[PASS] 5c. 7 bipagens unitárias completam o item (AC4.4)

--- CASO 6: pesável (KG) — fator não bloqueia ---
[PASS] 6a. 6 bipagens em item KG (pede 5) não geram erro — pesável isento de teto (AC4.3)
[PASS] 6b. quantidade_bipada = 6 (acima do pedido, permitido para KG)

--- CASO 7: não-regressão — produto sem Sonda ---
[PASS] 7a. biparItem sem Sonda retorna success (AC2.2)
[PASS] 7b. quantidade_bipada = 1 (fator=1, AC2.2)
[PASS] 7c. 1 extrato gravado (sem Sonda, fator=1)
[PASS] 7d. payload.fator = 1 (fator unitário preservado)

====================================================
RESULTADO: PASS=42  FAIL=0
TODOS OS TESTES PASSARAM
```

## Bugs encontrados

Nenhum bug de produção encontrado. Um único ajuste no teste foi necessário:

- **GalaxiaStub insuficiente (bug do teste, não de produção):** o stub inicial não implementava `atualizarPagina()`, que é chamado por `MissoesStatus::iniciarMissao()` via a cadeia fluente do `galaxiaResposta`. Corrigido no teste com `__call` fluente genérico (qualquer método exceto `feito()` retorna `$this`). O código de produção `MissoesStatus` é correto.
