# Logs do Sistema — Estratégia de Testes

> O módulo **não tem testes** na v6. A suíte existente
> (`v6/tests/Feature/`) cobre apenas o Dashboard e a configuração GA.
> Este dossiê define a cobertura necessária.

---

## 1. Precedente de harness

Reutilizar `v6/tests/DashboardTestCase.php`:

| Helper | Uso neste módulo |
|---|---|
| `createRole($slug, array $permissions)` | criar o perfil com `logs-do-sistema.index` |
| `createUser($roleSlug, array $permissions)` | criar e autenticar o operador que vai consultar a trilha |
| `setModules(array $statuses)` | **essencial** para testar a visibilidade do item de menu (`['logs-do-sistema' => true]`) |
| `DatabaseTransactions` | rollback automático |
| `withoutMiddleware(VerifyCsrfToken::class)` | dispensa CSRF |
| `require_once app/Library/Helper/appHelpers.php` | garante `has_access()` carregado |

> `setModules()` faz `DB::table('modulos')->where('slug', 'logs-do-sistema')->update(...)`
> — com a duplicidade, **as duas linhas** são atualizadas. Isso é útil para
> o teste da duplicidade, mas exige um teste que conserte o estado.

---

## 2. Estratégia

| Tipo | Escopo |
|---|---|
| **Feature** | Visibilidade do item de menu; acesso à tela `/cms/log`; endpoint AJAX; conteúdo retornado |
| **Unit** | `ActivityObserver` (higienização do user-agent); `struct_logs()` (formatação) |
| **Integração** | Migration de consolidação da duplicidade; migração `properties` → `jsonb` |

---

## 3. Fixtures necessárias

### 3.1 Factory

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

    public function definition(): array
    {
        return [
            'log_name'    => 'default',
            'action'      => 'custom',
            'description' => 'Listou usuários',
            'subject_type'=> User::class,
            'subject_id'  => 1,
            'causer_type' => User::class,
            'causer_id'   => 1,
            'properties'  => ['Detalhe' => 'Listado por: Administrador'],
            'ip_address'  => '127.0.0.1',
            'browser'     => 'Chrome 130.0.0.0',
            'created_at'  => now(),
        ];
    }
}
```

### 3.2 Seeders de ambiente

| Seed | Caminho | Papel |
|---|---|---|
| `PermissionsTableSeeder` | `v6/database/seeds/PermissionsTableSeeder.php` | as 9 ações atômicas |
| `ResourcesTableSeeder` | `v6/database/seeds/ResourcesTableSeeder.php` | catálogo de recursos |
| `RolesTableSeeder` | `v6/database/seeds/RolesTableSeeder.php` | perfis base |

### 3.3 Cenário de duplicidade

Para testar a duplicidade é preciso o estado real: **duas** linhas em
`modulos` com o mesmo slug. Se a migration de consolidação já tiver sido
aplicada no ambiente de teste, o caso deve ser reproduzido com um seeder
dedicado:

```php
// tests/Support/DuplicatedModuleSeeder.php
DB::table('modulos')->insert([
    ['name' => 'Logs do Sistema', 'slug' => 'logs-do-sistema', 'status' => true,  'created_at' => now(), 'updated_at' => now()],
    ['name' => 'Logs do Sistema', 'slug' => 'logs-do-sistema', 'status' => false, 'created_at' => now(), 'updated_at' => now()],
]);
```

---

## 4. Casos de teste

### 4.1 Visibilidade do item de menu (a duplicidade)

| # | Arrange | Act | Assert |
|---|---|---|---|
| M1 | Duas linhas `logs-do-sistema` (ids 7 e 32), a 32 com `status = false` | `Modulos::all()->pluck('status','slug')` | `['logs-do-sistema' => false]` — **a última linha vence** |
| M2 | Idem | renderizar o layout do AdminLTE | o HTML **não** contém "Logs do sistema" |
| M3 | Idem, com `super-admin` autenticado | renderizar o layout | o HTML **não** contém "Logs do sistema" (o `&& $modulos[...]` falha mesmo para super-admin) |
| M4 | Uma única linha com `status = true` | renderizar o layout | o HTML **não** contém "Logs do sistema" — porque `has_access(['registro-de-atividades.index'])` falha (slug inexistente) |
| M5 | Uma única linha com `status = true` **e** um recurso `registro-de-atividades` | renderizar o layout | o HTML **contém** "Logs do sistema" |
| M6 | Idem | `GET /cms/modulos` | o HTML contém **duas** linhas com o texto "Logs do Sistema" |
| M7 | Após a migration de consolidação | `DB::table('modulos')->where('slug','logs-do-sistema')->count()` | `1` |
| M8 | Após a migration de consolidação | `pluck('status','slug')` | `['logs-do-sistema' => true]` |

> M4/M5 documentam o segundo defeito: mesmo corrigindo a duplicidade, o
> item de menu **continua oculto** porque a permissão exigida
> (`registro-de-atividades.index`) não existe no catálogo `resources`.

### 4.2 Acesso à tela

| # | Arrange | Act | Assert |
|---|---|---|---|
| A1 | Sem autenticação | `GET /cms/log` | redirect (middleware `check.logged`) |
| A2 | Usuário autenticado sem nenhuma permissão | `GET /cms/log` | **200** (não há checagem de permissão) — comportamento atual; na v7 deve ser 403 |
| A3 | `super-admin` | `GET /cms/log` | 200 + view `admin.activities-logs.index` |
| A4 | `super-admin` | `GET /cms/log/create` | **500** (método inexistente) — comportamento atual; na v7 a rota não deve existir |
| A5 | `super-admin` | `DELETE /cms/log/1` | **500** — idem |

### 4.3 Endpoint AJAX

| # | Arrange | Act | Assert |
|---|---|---|---|
| D1 | 3 registros em `activity_log` | `GET /cms/datatable/logs` | JSON com 3 linhas; cada uma com `value`, `data`, `descricao`, `detalhes`, `ip`, `navegador` |
| D2 | Registro com `properties = {"Detalhe":"X","Outro":["a","b"]}` | `GET /cms/datatable/logs` | `detalhes` contém `Detalhe: X | Outro: ["a","b"] | ` |
| D3 | Registro com `properties = NULL` | `GET /cms/datatable/logs` | não gera warning/fatal (comportamento atual gera warning em PHP 8) |
| D4 | 6000 registros | `GET /cms/datatable/logs` | retorna **5000** linhas — comportamento atual; na v7 deve paginar |
| D5 | Registros com `created_at` distintos | `GET /cms/datatable/logs` | a ordem é **crescente** (bug do duplo `orderBy`) — na v7 deve ser decrescente |

### 4.4 Observer

| # | Arrange | Act | Assert |
|---|---|---|---|
| O1 | `User-Agent: Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36` | criar um log | `browser` não contém "Chrome/130" nem "Safari/537.36" |
| O2 | `User-Agent: ... Chrome/131.0.0.0 Safari/537.36` | criar um log | `browser` **contém** "Chrome/131" (bug do regex fixo) — registrar como bug |
| O3 | `User-Agent: ... OPR/120.0.0.0 ...` | criar um log | `browser` contém "Opera 120.0.0.0" |
| O4 | `User-Agent: ... Edg/120.0.0.0 ...` | criar um log | `browser` contém "Edge 120.0.0.0" |
| O5 | Qualquer requisição | criar um log | `ip_address` preenchido |

### 4.5 Gravação (comportamento atual)

| # | Arrange | Act | Assert |
|---|---|---|---|
| G1 | Usuário autenticado | `GET /cms/usuario` | 1 linha em `activity_log` com `description = 'Listou usuários'` e `properties.Detalhe` contendo o nome |
| G2 | `super-admin` | `POST /cms/usuario` | 1 linha com `description = 'Cadastro de usuário'` |
| G3 | Usuário autenticado | `POST /login` | 1 linha com `description = 'Login no sistema'` |
| G4 | Usuário autenticado | `GET /cms/perfil` | 1 linha com `description = 'Listou Roles'` |
| G5 | `Prefecture\SupportController` | enviar e-mail de suporte | 1 linha com `causer_id = NULL` (falta `causedBy`) — bug a corrigir |
| G6 | Qualquer ação | criar log | `log_name = 'default'` (nunca há `logName()`) |
| G7 | `Admin\UserController@store` | criar log | `subject_id` preenchido com o id do novo usuário |
| G8 | `Admin\UserController@index` | criar log | `subject_id = NULL` (o subject é uma instância nova do model) |

### 4.6 Integridade da tabela `modulos`

| # | Arrange | Act | Assert |
|---|---|---|---|
| I1 | Schema da v6 | `Schema::getColumnListing('modulos')` | não há índice único em `slug` (bug) |
| I2 | Após a migration de consolidação | tentar inserir um slug duplicado | exceção de violação de unicidade |
| I3 | Após a migration de consolidação | `resources.modulo_id` do recurso `logs-do-sistema` | aponta para o módulo **ativo** |

---

## 5. Como rodar

```bash
cd v6/
composer install
./vendor/bin/phpunit --testsuite Feature
./vendor/bin/phpunit tests/Feature/Logs/ModuleVisibilityTest.php
./vendor/bin/phpunit --filter testModuloLogsApareceNoMenu
```

Ambiente (de `v6/phpunit.xml`):

```xml
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
```

> A suíte usa `DatabaseTransactions`. O banco de teste precisa estar
> migrado; a migration de consolidação da duplicidade precisa estar
> aplicada (ou o caso de teste precisa recriar a duplicidade com o seeder
> da seção 3.3).

---

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

| Arquivo de teste | Casos |
|---|---|
| `tests/Feature/Logs/ModuleVisibilityTest.php` | M1-M8, I1-I3 |
| `tests/Feature/Logs/LogIndexTest.php` | A1-A5 |
| `tests/Feature/Logs/LogDatatableTest.php` | D1-D5 |
| `tests/Feature/Logs/AuditTrailTest.php` | G1-G8 |
| `tests/Unit/ActivityObserverTest.php` | O1-O5 |
| `tests/Feature/Logs/ConsolidateDuplicateModuleTest.php` | I2-I3 |

Meta: cobrir 100% de `ActivityObserver`, `struct_logs` e a migration de
consolidação; e garantir que **exista exatamente uma** linha em
`modulos` por slug, com um teste genérico que iterate todos os slugs.
