# LGPD (Barra de Privacidade) — Testes

> **Versão analisada:** `v6` (referência para o plano de testes da v7)
> **Slug do módulo:** `lgpd`

---

## 1. Situação atual (v6)

O módulo **não possui nenhum teste automatizado** no legado. Não há pasta
`tests/` do módulo, nem testes de feature/unit para as views de barra de
privacidade, nem para `Portal\HelperController@getPrivacyBar`. A verificação
atual é manual (navegador) ou por inspeção do banco.

O plano abaixo é o **alvo da v7**, mas os casos marcados como "legado" podem
ser executados hoje para caracterizar o comportamento atual (por exemplo,
como teste de caracterização antes da reescrita).

## 2. Estratégia

| Tipo | Ferramenta sugerida | Cobertura |
|---|---|---|
| Feature (HTTP) | Pest / PHPUnit + `RefreshDatabase` | Rotas do CMS, rotas públicas, renderização da barra no portal. |
| Unit | Pest / PHPUnit | `DataMaskTrait` (mascaramento), validações do Form Request, sanitização do HTML. |
| Component (view) | Pest | Condições de renderização da barra (`$modulos`, `$configurations`). |
| E2E | Playwright / Dusk | Fluxo completo de aceite do cidadão (cookie). |

Estratégia de dados: `factory(PrivacyBar::class)` com estados
`disabled()`, `enabled()`, `withText()`.

## 3. Fixtures necessárias

```php
// database/factories/PrivacyBarFactory.php (ilustrativo)
class PrivacyBarFactory extends Factory
{
    protected $model = PrivacyBar::class;

    public function definition(): array
    {
        return [
            'enabled' => false,
            'text' => '<p>Ao continuar navegando no nosso portal, você concorda com a nossa Política de Privacidade.</p>',
            'expiry_days' => 7,
            'button_text_color' => '#ffffff',
            'cookie_name' => 'acceptCookies',
        ];
    }

    public function enabled(): static
    {
        return $this->state(fn () => ['enabled' => true]);
    }
}
```

Para a transpilação do estado legado, uma fixture de seed equivalente:

```php
// database/seeders/PrivacyBarSeeder.php (ilustrativo)
public function run(): void
{
    PrivacyBar::updateOrCreate(
        ['prefecture_id' => 1],
        [
            'enabled' => false,
            'text' => 'Ao continuar navegando no nosso portal, você concorda com a nossa Política de Privacidade.',
            'expiry_days' => 7,
            'button_text_color' => '#ffffff',
        ]
    );
}
```

> O legacy já tem equivalente: `v6/database/seeds/ConfigurationsTableSeeder.php:1047-1105`
> (4 chaves) e `v6/database/seeds/DefaultSettingSeeder.php:92-97` (valores padrão).

## 4. Casos de teste — CMS (feature)

| # | Arrange | Act | Assert | Tipo |
|---|---|---|---|---|
| CMS-1 | Usuário autenticado com permissão `lgpd.view`; `PrivacyBar` existente | `GET /cms/configuracoes/editar/barra-privacidade` | Status 200; view renderizada; título "LGPD" presente | Feature |
| CMS-2 | Usuário **sem** `lgpd.view` | `GET /cms/configuracoes/editar/barra-privacidade` | Redirect para `dashboard.index`; mensagem de permissão | Feature |
| CMS-3 | Usuário com `lgpd.update`; request com `text`, `expiry_days = 30`, `enabled = true`, `button_text_color = '#123456'` | `PUT /admin/privacy-bar` | Registro atualizado no banco; redirect de sucesso | Feature |
| CMS-4 | `expiry_days = 0` | `PUT /admin/privacy-bar` | 422; mensagem "expiry_days deve ser no mínimo 1" | Feature |
| CMS-5 | `button_text_color = 'azul'` | `PUT /admin/privacy-bar` | 422 (regex de cor) | Feature |
| CMS-6 | `text` com `<script>alert(1)</script>` | `PUT /admin/privacy-bar` | Texto sanitizado (sem `<script>`) | Feature |
| CMS-7 | Usuário sem `lgpd.update` | `PUT /admin/privacy-bar` | 403; banco inalterado | Feature |
| CMS-8 | Usuário com `lgpd.update` | Item do menu do CMS | Link "LGPD" presente | Component |
| CMS-9 | Usuário sem `lgpd.view` | Item do menu do CMS | Link "LGPD" ausente | Component |
| CMS-10 | Exclusão de `cor_1` (categoria `site`) | `GET /` (portal) | Página renderiza sem erro (regressão do `first()->value`) | Regressão |

## 5. Casos de teste — Portal / público (feature)

| # | Arrange | Act | Assert | Tipo |
|---|---|---|---|---|
| PUB-1 | `PrivacyBar` com `enabled = true` e texto | `GET /` | HTML contém `class="barradeprivacidade"` (ou o equivalente v7) e o texto | Feature |
| PUB-2 | `enabled = false` | `GET /` | HTML **não** contém a barra | Feature |
| PUB-3 | `enabled = true`, sem cookie | `GET /` | JS presente; estado inicial "não aceitou" | Feature |
| PUB-4 | `enabled = true`, cookie `acceptCookies` válido | `GET /` | Barra não exibida | E2E |
| PUB-5 | Cookie expirado | `GET /` | Barra exibida novamente | E2E |
| PUB-6 | `GET /getPrivacyBar` (rota legada) | GET | `{"key":"barra-privacidade-expiracao","value":"7"}` | Feature (legado) |
| PUB-7 | `GET /api/privacy-bar` | GET | JSON com `enabled`, `text`, `expiry_days`, `cookie_name` | Feature |
| PUB-8 | `POST /api/privacy-bar/consent` com cookie ausente | POST | Registro criado em `privacy_bar_consents`; `Set-Cookie` com `Secure`, `SameSite=Lax`, `HttpOnly`, `Max-Age = expiry_days*86400` | Feature |
| PUB-9 | `POST /api/privacy-bar/consent` repetido | POST | 201; linha anterior mantida (histórico) | Feature |
| PUB-10 | `enabled = false` | `POST /api/privacy-bar/consent` | 404/409 (não há barra para consentir) | Feature |

## 6. Casos de teste — component view (condições de renderização)

| # | Variáveis | Assert |
|---|---|---|
| V-1 | `$modulos['lgpd'] = false`, demais condições válidas | Barra ausente |
| V-2 | `$modulos['lgpd'] = true`, `barra-privacidade-exibir = 0` | Barra ausente |
| V-3 | `$modulos['lgpd'] = true`, `barra-privacidade-exibir = '1'` (string) | Barra presente (comparação loose `== true`) |
| V-4 | `barra-privacidade` ausente do array | Barra ausente |
| V-5 | `barra-privacidade` presente com valor vazio | Barra presente, container vazio |
| V-6 | Texto com HTML | HTML renderizado sem escape (ou escapado na v7 — decisão explícita) |

## 7. Casos de teste — unitários (mascaramento / validação)

| # | Alvo | Entrada | Assert |
|---|---|---|---|
| U-1 | `DataMaskTrait::maskTextDeterministic()` | "CPF 123.456.789-00" | "123.***.***-00" |
| U-2 | `DataMaskTrait::maskTextDeterministic()` | "joao@exemplo.com" | e-mail com local mascarado |
| U-3 | `DataMaskTrait::maskTextWithAi()` sem `gemini_api_key` | texto qualquer | retorna a máscara determinística (fallback local) |
| U-4 | Form Request (legado `ConfigurationRequest`) | `barra-privacidade-expiracao = "abc"` | Em `v6` **passa** (sem regra); na v7 deve falhar (inteiro) |
| U-5 | `DataMaskTrait` + "35 anos, tuberculose" | frase | dado sensível mascarado |

## 8. Testes de caracterização do legado (executáveis antes da reescrita)

Objetivo: fixar o comportamento atual para detectar regressões na migração.

| # | Cenário legado | Resultado esperado (medido no v6) |
|---|---|---|
| LEG-1 | `modulos.status = 0` para `lgpd` + `barra-privacidade-exibir = 1` | Barra **ausente** no HTML do portal |
| LEG-2 | `modulos.status = 1` + `barra-privacidade-exibir = 1` | Barra presente |
| LEG-3 | `modulos.status = 1` + `barra-privacidade-exibir = 0` | Barra ausente |
| LEG-4 | `GET /cms/configuracoes/editar/barra-privacidade` sem `barra-privacidade.edit` | Redirect para `dashboard.index` |
| LEG-5 | `POST /cms/update/configuration` sem `configuracoes.edit` | Redirect para `dashboard.index`, nada gravado |
| LEG-6 | `POST /cms/update/configuration` com `category_configurations_id` da LGPD e `barra-privacidade-exibir = 1` | Linha 72 da tabela `configurations` atualizada |
| LEG-7 | `GET /getPrivacyBar` | JSON com `key` e `value` |
| LEG-8 | `GET /` com `cor_1` removida | Erro 500 (bug conhecido do `first()->value`) |

## 9. Como rodar

Legado (v6) — não há suíte do módulo; suíte geral:

```bash
cd v6
./vendor/bin/phpunit --filter Configuration
```

Ambiente de banco (somente leitura para conferência — **nunca** rodar
migration/seed em produção):

```bash
docker exec v6_6f22e1bd-postgres-1 psql -U postgres -d prefeituras_v5 -c \
"select c.\"key\", c.value from configurations c join category_configurations cc on cc.id = c.category_configurations_id where cc.slug = 'barra-privacidade';"
```

v7 (alvo):

```bash
php artisan test --filter=PrivacyBar
php artisan test --testsuite=Feature --filter=PrivacyBarConsent
vendor/bin/pest tests/Feature/PrivacyBarTest.php
```

## 10. Checklist de QA manual (portal)

1. Ativar o módulo `lgpd` em `/cms/modulos`.
2. Em `/cms/configuracoes/editar/barra-privacidade`, marcar "Ativar barra de
   privacidade", gravar texto, prazo e cor; salvar.
3. Abrir o portal em janela anônima → a faixa deve aparecer.
4. Clicar "Ok, entendi!" → a faixa deve sumir em ~1 s.
5. Recarregar → a faixa não deve aparecer (cookie válido).
6. Apagar cookies → a faixa deve voltar.
7. Alterar o prazo para 1 dia → repetir os passos 3..6.
8. Confirmar que a cor do texto do botão segue a configuração e a borda segue
   `cor_1` do módulo `../configuracoes-da-instituicao/`.
9. Verificar no console do navegador a ausência de 404 no recurso
   `assets/css/portal/privacybar/style.css` (bug conhecido: **ocorre**).
