# e-Vacina — Estratégia de Testes

> O módulo **não tem testes** na v6. A suíte existente
> (`v6/tests/`) cobre apenas o Dashboard e a configuração GA.

---

## 1. Precedente de harness

`v6/tests/DashboardTestCase.php`:
`createRole()`, `createUser()`, `setModules()`, `DatabaseTransactions`,
`withoutMiddleware(VerifyCsrfToken::class)`.

Para este módulo:
- `setModules(['e-vacina' => true])` — necessário para o item de menu
  (o módulo nasce **desativado**);
- `createRole('vacinador', ['e-vacina.index', 'e-vacina.edit'])`.

---

## 2. Estratégia

| Tipo | Escopo |
|---|---|
| **Feature** | Leitura, gravação, **autorização** (as rotas são públicas!), o botão de submit |
| **Unit** | Importação do CSV: contagem das doses, parsing da URL |
| **Integration** | Comando `reload:evacina` com HTTP fake |

---

## 3. Fixtures necessárias

### 3.1 Factory

```php
// database/factories/EvacinaConfigFactory.php
class EvacinaConfigFactory extends Factory
{
    protected $model = EvacinaConfig::class;

    public function definition(): array
    {
        return [
            'population' => 500000,
            'source_url' => 'https://docs.google.com/spreadsheets/d/FAKE_ID/edit#gid=123',
            'is_active'  => true,
        ];
    }
}
```

### 3.2 CSV de teste

Para o teste da importação, um CSV local com a coluna 28 preenchida:

```csv
name,dose,....
Alice,Dose
Bob,1ª Dose
Carla,2ª Dose
Daniel,Dose Adicional
Eva,Reforço
Fábio,2ª Reforço
```

> Cada linha precisa de **28 colunas** antes da de doses (o índice 28
> é a 29ª coluna). O CSV de teste deve ter 29 campos por linha.

### 3.3 HTTP fake

O comando usa `file_get_contents` (v6) — na v7, com `Http::fake()`:

```php
Http::fake([
    'docs.google.com/*' => Http::response(
        file_get_contents(base_path('tests/Fixtures/vacinas.csv')),
        200
    ),
]);
```

---

## 4. Casos de teste

### 4.1 Autorização (o item mais crítico)

| # | Arrange | Act | Assert |
|---|---|---|---|
| A1 | **Sem autenticação** | `GET /cms/e-vacina` | **v6: 200** (rota pública); **v7: 401/302** |
| A2 | Sem autenticação | `POST /cms/e-vacina` | **v6: aceito**; **v7: 401/403** |
| A3 | Sem autenticação | `PUT /cms/e-vacina/1` | **v6: aceito**; **v7: 401/403** |
| A4 | Usuário sem `e-vacina.index` | `GET /cms/e-vacina` | **v6: 200**; **v7: 403** |
| A5 | Perfil com `e-vacina.index` | `GET /cms/dashboard` | o link "e-Vacina" aparece (módulo ligado) |
| A6 | Módulo `e-vacina` **desativado** | `GET /cms/dashboard` | o link **não** aparece |
| A7 | Perfil com `e-vacina.index` | `GET /cms/e-vacina` | 200 + view `prefecture.configurations.evacina.edit` |

### 4.2 Leitura e gravação

| # | Arrange | Act | Assert |
|---|---|---|---|
| M1 | Nenhum registro | `GET /cms/e-vacina` | 200 + o formulário com a imagem de exemplo |
| M2 | Registro existente | `GET /cms/e-vacina` | 200 + o formulário preenchido (população, url, imagem) |
| M3 | Idem | o `<form action=...>` | **v6**: `cms/e-vacina/1` (id fixo); **v7**: rota sem id |
| M4 | Usuário autenticado | `POST /cms/e-vacina` com url, populacao e a checkbox marcada | linha criada; `status = true` |
| M5 | Idem, **sem** a checkbox | `POST /cms/e-vacina` | **v6**: `status = null`; **v7**: `status = false` |
| M6 | Idem, `populacao = 0` | `POST /cms/e-vacina` | **v6**: `null` em coluna NOT NULL -> erro; **v7**: 422 (`min:1`) |
| M7 | Idem, `url` inválida | `POST /cms/e-vacina` | **v6**: aceita; **v7**: 422 |
| M8 | Registro existente | `PUT /cms/e-vacina/999` (id inexistente na URL) | **v6**: o registro **mais recente** é atualizado; **v7**: 404 |
| M9 | Nenhum registro | `PUT /cms/e-vacina/1` | **v6**: erro fatal (`null->id()`); **v7**: 404/422 |
| M10 | Idem | `POST /cms/e-vacina` duas vezes | 2 linhas criadas (o `store` sempre insere) — **v7**: 1 linha (upsert) |
| M11 | Usuário autenticado | o botão "Registrar" | **v6**: o clique **não** submete (botão fora do `<form>`); **v7**: submete |

### 4.3 Importação (comando / service)

| # | Arrange | Act | Assert |
|---|---|---|---|
| I1 | Config com `status = false` | `reload:evacina` | os contadores **não** são atualizados (comportamento atual) |
| I2 | Config com `status = true` e CSV fake | `reload:evacina` | `first_dose = 2` (`Dose` + `1ª Dose`), `second_dose = 1`, `first_booster = 2` (`Dose Adicional` + `Reforço`), `second_booster = 1` |
| I3 | URL sem `spreadsheets/d/` | `reload:evacina` | **v6**: falhou silenciosamente; **v7**: exceção com mensagem clara |
| I4 | URL sem `gid=` | `reload:evacina` | idem |
| I5 | HTTP 500 na planilha | `reload:evacina` | **v6**: nada registrado; **v7**: `Log::warning` gravado |
| I6 | Planilha inacessível (timeout) | `reload:evacina` | **v7**: a requisição não trava (timeout de 30 s) |
| I7 | CSV com coluna 28 vazia | `reload:evacina` | contadores zerados; **v7**: log do cabeçalho detectado |

### 4.4 Modelo e schema

| # | Arrange | Act | Assert |
|---|---|---|---|
| C1 | Base migrada | `DB::table('resources')->where('slug','e-vacina')->exists()` | **hoje: `true`** (id 46) |
| C2 | Base migrada | `modulos` com `slug = 'e-vacina'` | `status = false` (desativado por padrão) |
| C3 | Schema | colunas de `evacinas` | `populacao` NOT NULL; `status` nullable; `deleted_at` presente |
| C4 | Model | `$model->getCasts()` | **v6**: sem casts; **v7**: `status` => boolean |

### 4.5 Auditoria

| # | Arrange | Act | Assert |
|---|---|---|---|
| S1 | Usuário autenticado | `POST /cms/e-vacina` | **v6**: nenhuma linha em `activity_log`; **v7**: 1 linha |

---

## 5. Fixtures de view

| View | Variáveis |
|---|---|
| `prefecture.configurations.evacina.edit` | `data` (model `Evacina` ou `null`) |
| `prefecture.configurations.evacina.form` | `data` (opcional), `errors` |

---

## 6. Como rodar

```bash
cd v6/
composer install
./vendor/bin/phpunit --testsuite Feature
./vendor/bin/phpunit tests/Feature/Evacina/EvacinaAuthorizationTest.php
./vendor/bin/phpunit --filter testRotaDeEscritaExigeAutenticacao
```

Ambiente (de `v6/phpunit.xml`): `APP_ENV=testing`,
`CACHE_DRIVER=array`, `SESSION_DRIVER=array`, `QUEUE_DRIVER=sync`.

> A suíte usa `DatabaseTransactions`; o banco de teste precisa estar
> migrado (a tabela `evacinas` é criada por migration) e com o recurso
> `e-vacina` presente (ele **já existe** na base).

---

## 7. Cobertura mínima aceitável para a v7

| Arquivo de teste | Casos |
|---|---|
| `tests/Feature/Evacina/EvacinaAuthorizationTest.php` | A1-A7 |
| `tests/Feature/Evacina/EvacinaCrudTest.php` | M1-M11 |
| `tests/Unit/SheetImporterTest.php` | I2-I4, I7 |
| `tests/Feature/Evacina/ReloadEvacinaCommandTest.php` | I1, I3-I6 |
| `tests/Feature/Evacina/EvacinaSchemaTest.php` | C1-C4 |
| `tests/Feature/Evacina/EvacinaAuditTest.php` | S1 |

Os casos **A1-A3** (rotas públicas) são o item de maior prioridade: na
v7, todos devem esperar 401/403.
