# Páginas Estáticas — Estratégia de Testes

## 1. Estratégia

| Tipo | Ferramenta | Foco |
|---|---|---|
| Feature (portal) | Pest/PHPUnit + `RefreshDatabase` | Renderização, 404, redirecionamento externo, slugs reservados, cliques |
| Feature (CMS) | Pest/PHPUnit | Permissões, validação condicional, proteção de páginas de sistema, galeria |
| Unit (model/repository) | PHPUnit | Slug único, desambiguação, `is_external` |
| Integração (view SQL) | PHPUnit sobre Postgres | Colunas expostas por `paginas_estaticas` |
| Contrato de rotas | PHPUnit | Ausência de rota duplicada `static.show` |

Não há suíte do módulo no legado. `v6/tests/` (34 arquivos) cobre apenas o
Dashboard.

## 2. Fixtures / factories

```php
// database/factories/StaticPageFactory.php
StaticPage::factory()->create([
    'title' => 'Institucional',
    'slug'  => 'institucional',
    'text'  => '<p>Texto da página</p>',
    'status_create' => false,
    'galery' => false,
    'layout' => StaticPageLayout::WITHOUT_SIDEBAR,
    'is_external' => false,
]);
```

| Factory | Campos | Variações |
|---|---|---|
| `StaticPageFactory` | `title`, `slug`, `text`, `status_create`, `galery`, `layout`, `is_external` | `->system()` (`status_create = true`), `->external($url)`, `->withGallery()` |
| `StaticPageFileFactory` | `static_page_id`, `name`, `path`, `highlight`, `view_pdf` | `->gallery()`, `->inlinePdf()` |
| `LinkFactory` | `static_pages_id`, `link`, `title` | `->external()`, `->youtube()` |

## 3. Casos de teste — Portal

| # | Arrange | Act | Assert |
|---|---|---|---|
| T01 | página com `layout = 2` | `GET /institucional` | 200; HTML do conteúdo; **sem** coluna de sidebar |
| T02 | página com `layout = 1` | `GET /institucional` | 200; sidebar presente |
| T03 | página inexistente | `GET /nao-existe` | **404** (comportamento a corrigir; hoje é 200 com "PÁGINA NÃO ENCONTRADA") |
| T04 | página com `is_external = true` e `links.link` | `GET /externo` | 302 para a URL externa |
| T05 | página com `is_external = true` **sem** link | `GET /externo` | erro controlado (não deve gerar "Trying to read property on null") |
| T06 | página com slug `contato` | `GET /contato` | 302 para `route('contato.index')` |
| T07 | página com slug `ouvidoria` | `GET /ouvidoria` | 302 para `route('ouvidoria.index')` |
| T08 | página com slug `solicitar-informacao` | `GET /solicitar-informacao` | 302 para `route('acesso-rapido.index', ...)` |
| T09 | página visitada 3 vezes | `GET /institucional` x3 | `clicks` = 3 |
| T10 | página externa visitada | `GET /externo` | `clicks` = 1 (comportamento atual — ver T21) |
| T11 | página com galeria | `GET /institucional` | a galeria é renderizada |
| T12 | página com `view_pdf = true` | `GET /institucional` | a lista de arquivos/PDF é renderizada |
| T13 | página com link de vídeo | `GET /institucional` | o player é renderizado |
| T14 | mesma página acessada por `/pagina/{slug}` | `GET /pagina/institucional` | 200 e o mesmo conteúdo |
| T15 | página com soft delete | `GET /institucional` | 404 (a view SQL e o `SoftDeletes` filtram) |

## 4. Casos de teste — CMS

| # | Arrange | Act | Assert |
|---|---|---|---|
| T20 | usuário sem `pagina-estatica.create` | `GET /cms/pagina-estatica` | o HTML não contém "Cadastrar Página Estática" |
| T21 | `GET /cms/datatable/paginas_staticas` | — | JSON com `titulo`, `slug`, `id` e os flags `edit`/`delete` |
| T22 | página com galeria | `GET /cms/datatable/paginas_staticas` | o campo `galery` **não** existe (bug da view) — registrar |
| T23 | payload sem `title` | `POST /cms/pagina-estatica` | erro em `title` |
| T24 | payload com slug já usado | `POST /cms/pagina-estatica` | erro "URL já existente" |
| T25 | payload com slug de `category_contents` | `POST /cms/pagina-estatica` | erro "URL já existente" |
| T26 | payload com slug `diario-oficial` | `POST /cms/pagina-estatica` | erro "URL já existente" (slug reservado) |
| T27 | payload com `is_external` e sem `link` | `POST /cms/pagina-estatica` | erro "O campo Link é obrigatório ao marcar a opção Redirecionar para Link Externo" |
| T28 | payload válido | `POST /cms/pagina-estatica` | 302; página criada; `slug` gerada; `is_external` gravado |
| T29 | página existente | `PUT /cms/pagina-estatica/{id}` | o conteúdo é atualizado; `is_external` convertido para booleano |
| T30 | página de sistema (`status_create = 1`) | `DELETE /cms/pagina-estatica/{id}` | JSON de erro "Esta página não pode ser deletada."; página intacta |
| T31 | página comum com `menu_items` | `DELETE /cms/pagina-estatica/{id}` | soft delete + `menu_items` removidos |
| T32 | lote com 1 página de sistema e 1 comum | `POST /cms/pagina-estatica/delete-por-lote` | só a comum é excluída |
| T33 | `GET /cms/pagina-estatica/{id}` (rota `show` sem método) | — | deve ser 404/redirect, **não** 500 (bug atual) |
| T34 | upload de imagem na galeria | `POST /cms/ajax-static-upload-files` | `archives` criado; arquivo em `storage/statics/{slug}/galeria/` |
| T35 | exclusão de arquivo da galeria | `POST /cms/ajax-static-delete-files-gallery` | arquivo removido do disco e do banco |
| T36 | anexo `.exe` | `POST /cms/pagina-estatica` | erro de extensões |
| T37 | página com galeria salva | `POST /cms/pagina-estatica` | redirect para `editar-pagina` com `#galeria` |

## 5. Casos de teste — view SQL

| # | Arrange | Act | Assert |
|---|---|---|---|
| T40 | 2 páginas + 1 deletada | `select * from paginas_estaticas` | 2 linhas; a deletada não aparece |
| T41 | — | `select * from paginas_estaticas` | as colunas são `value`, `titulo`, `slug`, `id` (**sem** `galery`) |
| T42 | 2 páginas com a mesma slug | `GET /{slug}` | devolve sempre a de menor `id` (bug atual) |

## 6. Casos de teste — rotas

| # | Arrange | Act | Assert |
|---|---|---|---|
| T50 | aplicação com as rotas carregadas | `Route::getRoutes()->getByName('static.show')` | apenas **uma** rota com esse nome (bug atual: duas) |
| T51 | — | `route('static.show', 'contato')` | URL canônica definida (bug atual: resolve para `/{slug}`) |
| T52 | — | `GET /` | não deve ser capturado pela rota `catch-all` |

## 7. Fixtures de seed para o ambiente de teste

```php
// tests/Seed/StaticPages.php
StaticPage::updateOrCreate(['slug' => 'contato'], [
    'title' => 'Contato', 'text' => '<p>Canal de contato</p>',
    'status_create' => true,
]);
StaticPage::updateOrCreate(['slug' => 'institucional'], [
    'title' => 'Institucional', 'text' => '<p>Sobre a prefeitura</p>',
    'status_create' => false, 'layout' => 2,
]);
```

Configuração necessária em `configurations`:

| key | value | efeito |
|---|---|---|
| `layout` | `modelo1` | template do portal (a view precisa existir) |

## 8. Como rodar

```bash
php artisan test
php artisan test --filter=StaticPage
php artisan test tests/Feature/Portal/StaticPageShowTest.php
php artisan test --coverage --min=80 --filter=StaticPage
```

Ambiente legado, para regressão manual:

```bash
cd v6
docker compose exec app php artisan route:list --name=static.show
```

## 9. Checklist de regressão manual

1. `/{slug}` e `/pagina/{slug}` devolvem a mesma página.
2. Página com `is_external` redireciona.
3. Página inexistente mostra "PÁGINA NÃO ENCONTRADA".
4. Slugs reservados redirecionam para os módulos correspondentes.
5. Página de sistema não pode ser excluída (nem individualmente nem em lote).
6. O botão "Ir para galeria" aparece após salvar com galeria ativa.
7. Upload e exclusão de arquivo da galeria funcionam.
8. O contador de cliques sobe a cada visita.
9. O botão de galeria na listagem do CMS está desabilitado (bug da view) —
   registrar para correção.
