# Testes

## 1. Situação atual

**O módulo não possui nenhum teste próprio.** `tests/Feature/V2/Modules/DadosAbertos/`
contém apenas `tests/Feature/V2/Modules/DadosAbertos/Operators/OperatorCmsControllerTest.php` e
`tests/Feature/V2/Modules/DadosAbertos/Operators/OperatorImportCmsTest.php` — o vizinho de grupo tem cobertura, a
Transparência Fiscal não.

Cobertura indireta (não exercita controllers/views do módulo):

| Teste | O que cobre | Referência |
|---|---|---|
| `tests/Feature/V2/Rbac/CommonUserModuleAccessE2ETest.php` | acesso de usuário comum à rota `v2.transparencia.items.index` em duas grafias de permissão | `:52` |
| `tests/Unit/V2/Modules/Infraestrutura/MigracaoLegada/TransparenciaFiscalLegacyImporterTest.php` | contrato do importador (map/load, idempotência, categoria, arquivos) | arquivo inteiro |
| `tests/Feature/V2/Modules/Infraestrutura/MigracaoLegada/LegacyNovosImportadoresEndpointsTest.php` | preview/run do importador pela rota de Support | `:49`, `:67` |

Nenhum teste cobre: listagem pública, detalhe por slug, N+1, itens inativos em
filhas, CRUD de itens, slug imutável, checkbox `is_active` no update.

## 2. Estratégia

| Camada | Tipo | Por quê |
|---|---|---|
| `TransparencyCmsController` | **Feature** | envolve middleware, Request, redirect, soft delete e auditoria — o comportamento só é observável na stack HTTP |
| `TransparencyPortalController` | **Feature** | precisa de banco para relações, escopos e 404 |
| `V2TransparencyItem` / `Category` | **Unit** | hooks de slug e escopos são puros o suficiente para teste rápido, mas exigem Eloquent (não são funções puras) |
| Views | **Feature** (assertSee) | evita teste de snapshot frágil; verifica conteúdo essencial e ausência |

Sem `DatabaseTransactions` global no módulo novo: usar a trait por classe, como
`tests/Feature/V2/Modules/Publicacoes/Licitacoes/LicitacaoCmsControllerTest.php`
faz (`:22-23`).

## 3. Casos propostos

### 3.1 Portal (6 casos)

| # | Arrange | Act | Assert |
|---|---|---|---|
| P1 | 1 raiz ativa com 2 itens ativos | `GET /transparencia` | 200; vê os 2 títulos; vê o nome da raiz |
| P2 | raiz ativa + filha ativa + item **inativo** na filha | `GET /transparencia` | **falha hoje**: o item inativo aparece; após correção, 200 sem o título |
| P3 | raiz ativa + filha ativa com 3 itens ativos | `GET /transparencia` | hoje: 1 query extra por filha; meta: `DB::listen` conta queries ≤ N fixo |
| P4 | item ativo com slug | `GET /transparencia/{slug}` | 200; valor `R$ 1.500,00`; data `02/05/2026`; categoria no bloco "Informações" |
| P5 | item **inativo** com slug | `GET /transparencia/{slug}` | 404 |
| P6 | raiz inativa com filha ativa | `GET /transparencia` | 200 e não vê a raiz nem a filha |

### 3.2 CMS — CRUD (6 casos)

| # | Arrange | Act | Assert |
|---|---|---|---|
| C1 | perfil `write` + categoria ativa | `POST /cms/v2/transparencia` com título/valor/data | redirect para index; banco tem 1 item; `audit_logs` tem `created` |
| C2 | item existente | `POST /cms/v2/transparencia/{id}` com novo título | item atualizado; **slug inalterado**; auditoria `updated` |
| C3 | item existente | `POST /cms/v2/transparencia/{id}/delete` | `deleted_at` preenchido; some do portal |
| C4 | payload sem título | `POST .../store` | 302 back com erro `O título é obrigatório.`; nada gravado |
| C5 | perfil `read` | `GET .../create` e `POST .../store` | 403/redirect; nada gravado |
| C6 | sem login | `GET .../index` | redirect para `v2.cms.login` |

### 3.3 Regras de slug e ordenação (4 casos)

| # | Arrange | Act | Assert |
|---|---|---|---|
| S1 | create com título "Folha de Pagamento — Maio 2026" | `V2TransparencyItem::create` | slug = `folha-de-pagamento-maio-2026-` concatenado aos 8 primeiros caracteres do UUID |
| S2 | item criado; alterar título | `update(['title' => 'Novo'])` | slug **permanece** — documenta o comportamento atual |
| S3 | 3 categorias com `order` 0, 2, 1 | `V2TransparencyCategory::ordered()->get()` | ordem 1, 2, 0-alfabética |
| S4 | duas categorias de raízes distintas com mesmo nome | `create` da segunda | hoje: viola `slug` unique — caso de regressão a corrigir |

### 3.4 Importador (já coberto — não duplicar)

`TransparenciaFiscalLegacyImporterTest` já valida:

- `description` = summary ou texto plano;
- `value` nulo;
- `reference_date` = data de `publication_date`;
- `is_active` a partir de `status`;
- recriação hierárquica de categorias (raiz inclusa);
- arquivos copiados para a galeria;
- idempotência por `v1_id`.

Basta referenciar em `07` e não reescrever.

## 4. Factories e fixtures necessárias

Não existem factories no projeto para estes models. Criar em
`database/factories/V2/` (ou inline no teste, como o padrão de Licitacoes faz):

```php
// exemplo ilustrativo
$root = V2TransparencyCategory::create([
    'name' => 'Receitas',
    'slug' => 'receitas',
    'is_active' => true,
    'order' => 1,
]);

$child = V2TransparencyCategory::create([
    'name' => 'Exploração de Jogos',
    'slug' => 'exploracao-de-jogos-' . uniqid(),
    'parent_id' => $root->id,
    'is_active' => true,
    'order' => 1,
]);

$item = V2TransparencyItem::create([
    'title' => 'Arrecadação — Janeiro 2026',
    'value' => 1500000.00,
    'reference_date' => '2026-01-31',
    'is_active' => true,
    'v2_transparency_category_id' => $child->id,
]);
```

Cuidados:

- `slug` de categoria é `unique` global — usar sufixo de teste (`uniqueid`/banda)
  para não colidir com o seed de ambiente;
- `V2EnvironmentSeeder` já cria `receitas`/`despesas`; os testes de portal devem
  contar apenas as categorias que criou ou limpar a tabela no `setUp`.

## 5. Autenticação e RBAC no teste

Reaproveitar o padrão de `LicitacaoCmsControllerTest`:

```php
// exemplo ilustrativo
$this->app->singleton(V2AuditLogger::class, function () {
    $mock = Mockery::mock(V2AuditLogger::class);
    $mock->shouldReceive('activity')->byDefault();
    return $mock;
});

$role = V2Role::create([
    'name' => 'Transparência Admin',
    'slug' => 'transparencia-admin-' . uniqid(),
    'permissions_v2' => ['TransparenciaFiscal' => 'write'],
]);

$user = new User(['name' => 'Admin', 'email' => 'admin.transp@test.com']);
$user->v2_role_id = $role->id;
$user->save();
Sentinel::login($user);
```

Para testes que chamam o controller diretamente, lembrar que
`TransparencyRequest::authorize()` exige `v2_can('transparencia','write')` — o
usuário precisa do perfil e do alias resolvido.

## 6. Fixtures de seed para ambiente de teste

| Fixture | Origem | Uso |
|---|---|---|
| Categorias padrão | `V2/Modules/DadosAbertos/TransparenciaFiscal/Seeds/TransparenciaSeeder.php` (`includeDemoData=false`) | smoke de instanciação do ambiente |
| 4 itens demo | `V2/Modules/DadosAbertos/TransparenciaFiscal/Seeds/TransparenciaSeeder.php` (`includeDemoData=true`) | testes de portal/contagem |
| Árvore V1 | `V2/Modules/Support/MigracaoLegada/Services/LegacyV1FixtureFactory.php:644-662` | testes do importador |

Nota: o seeder usa `withTrashed()` e reativa categorias — em teste, isso pode
mascarar um cenário de "categoria excluída". Preferir criar dados próprios.

## 7. Como rodar

```bash
cd /home/one/projects/maxima/v7/lotep

# todos os testes de transparência (novos + indiretos)
vendor/bin/phpunit --filter 'Transparencia|Transparency|CommonUserModuleAccess'

# somente o módulo (após criar os arquivos)
vendor/bin/phpunit tests/Feature/V2/Modules/DadosAbertos/TransparenciaFiscal

# suíte completa (baseline: 650 testes / 2107 asserções / 9 skipped)
vendor/bin/phpunit

# e2e (89 casos, token de avaliação)
vendor/bin/phpunit --testsuite Feature
```

Observação: o projeto usa PHP 7.4 e PHPUnit do Laravel 5.5; não há Pest. Os
testes novos seguem `Tests\TestCase` + `DatabaseTransactions`.

## 8. Critérios de aceite dos testes novos

1. Os 6 casos de portal passam **após** a correção do filtro `active()` em
   `children.items`; os casos P2/P3 devem falhar antes da correção (prova de que
   o teste detecta o bug).
2. O caso S2 documenta o comportamento atual (slug imutável) e deve ser
   substituído no porte V7 por "slug é editável e único".
3. Nenhum teste novo depende da ordem de registro de rotas do Laravel 5.5.
4. Auditoria é mockada; não escrever no sink real durante os testes.
