# Orvox Influencers — Test Suite Completa

Este pacote adiciona uma suíte de testes para o MVP **Orvox Influencers**, cobrindo testes unitários, feature tests com mocks HTTP, testes de webhook, privacidade do painel do influencer, gamificação, fechamento mensal e um fluxo E2E assistido contra a Nuvemshop real.

> Este zip é um **overlay**: descompacte dentro da raiz do projeto Laravel. Ele não substitui o projeto inteiro.

---

## 1. Como instalar no projeto

Na raiz do projeto:

```bash
unzip orvox-influencers-test-suite.zip -d /tmp/orvox-tests
cp -R /tmp/orvox-tests/overlay/* .
```

Depois limpe cache:

```bash
./vendor/bin/sail artisan optimize:clear
./vendor/bin/sail artisan config:clear
./vendor/bin/sail artisan route:clear
```

Se os novos comandos Artisan não aparecerem no `artisan list`, registre a pasta de comandos no `bootstrap/app.php`:

```php
->withCommands([
    __DIR__.'/../app/Console/Commands',
])
```

Exemplo completo do trecho:

```php
return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withCommands([
        __DIR__.'/../app/Console/Commands',
    ])
    ->withMiddleware(function (Middleware $middleware): void {
        // ...
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        // ...
    })
    ->create();
```

---

## 2. Rodar todos os testes automatizados locais

Os testes locais usam SQLite em memória e `Http::fake()`, então não mexem na Nuvemshop real.

```bash
./vendor/bin/sail test
```

Ou:

```bash
./vendor/bin/sail artisan test
```

Rodar por grupos/pastas:

```bash
./vendor/bin/sail test tests/Unit
./vendor/bin/sail test tests/Feature/Admin
./vendor/bin/sail test tests/Feature/Nuvemshop
./vendor/bin/sail test tests/Feature/Webhooks
./vendor/bin/sail test tests/Feature/Influencer
./vendor/bin/sail test tests/Feature/Gamification
./vendor/bin/sail test tests/Feature/Settlements
```

---

## 3. Arquivos adicionados

### Suporte de testes

```text
tests/Support/InteractsWithOrvoxTestData.php
```

Cria rapidamente:

- tenant Orvox fake;
- store fake;
- provider Nuvemshop;
- integração fake com token criptografado;
- admin principal;
- influencer;
- cupom;
- pedido;
- comissão;
- regras de gamificação;
- payloads Nuvemshop simulados.

### Unitários

```text
tests/Unit/CouponNormalizationTest.php
tests/Unit/CommissionCalculatorUnitTest.php
```

### Feature/admin

```text
tests/Feature/Admin/InfluencerCreationTest.php
```

### Feature/Nuvemshop com mock

```text
tests/Feature/Nuvemshop/NuvemshopAuthAndTokenTest.php
tests/Feature/Nuvemshop/NuvemshopCouponLifecycleTest.php
tests/Feature/Nuvemshop/NuvemshopOrderSyncTest.php
tests/Feature/Nuvemshop/NuvemshopProductAndWebhookRegistrationTest.php
tests/Feature/Nuvemshop/NuvemshopCouponUpdateDeleteContractTest.php
```

### Webhooks

```text
tests/Feature/Webhooks/NuvemshopWebhookTest.php
```

### Privacidade influencer

```text
tests/Feature/Influencer/InfluencerDashboardPrivacyTest.php
```

### Gamificação

```text
tests/Feature/Gamification/GamificationServiceTest.php
```

### Fechamento e pagamento manual

```text
tests/Feature/Settlements/SettlementServiceTest.php
```

### Testes reais opcionais contra Nuvemshop

```text
tests/Feature/Nuvemshop/NuvemshopRealSmokeTest.php
```

Por padrão, estes testes reais ficam pulados. Para rodar, precisa configurar variáveis específicas.

### Services auxiliares para E2E

```text
app/Services/Nuvemshop/NuvemshopProductService.php
app/Services/Nuvemshop/NuvemshopWebhookRegistrationService.php
```

### Commands E2E

```text
app/Console/Commands/RunNuvemshopE2ECommand.php
app/Console/Commands/CleanupNuvemshopE2ECommand.php
```

---

# 4. Explicação detalhada dos testes

## 4.1 `CouponNormalizationTest`

Valida que o sistema normaliza cupons para comparação interna:

- `Maria10` vira `MARIA10`;
- `  ana20  ` vira `ANA20`;
- comparação interna não depende de maiúsculas/minúsculas.

Importância: evita duplicidade de cupom por variação de caixa.

---

## 4.2 `CommissionCalculatorUnitTest`

Testa cálculo puro de comissão:

- R$ 180,00 com 8% gera R$ 14,40;
- R$ 180,00 com 10% gera R$ 18,00;
- arredondamento para 2 casas decimais.

Importância: garante que o valor seja calculado sobre a base correta, sem frete.

---

## 4.3 `InfluencerCreationTest`

Cobre o cadastro administrativo de influencer:

- admin cria influencer;
- usuário de login do influencer é criado junto;
- role fica como `influencer`;
- status fica `active`;
- e-mail duplicado é bloqueado;
- admin consegue inativar influencer e usuário vinculado.

Importância: valida o fluxo principal do painel admin.

---

## 4.4 `NuvemshopAuthAndTokenTest`

Cobre OAuth e armazenamento seguro:

- troca de `authorization_code` por `access_token` usando `Http::fake()`;
- salva `user_id/external_store_id`;
- salva scopes;
- token fica criptografado no banco;
- model devolve token descriptografado.

Importância: evita copiar token criptografado do banco e tomar `401 Invalid access token` nos cURLs.

---

## 4.5 `NuvemshopCouponLifecycleTest`

Cobre criação de cupom com mock da Nuvemshop:

- cria cupom na Nuvemshop antes de salvar localmente;
- salva `external_coupon_id` retornado;
- salva `coupon_code_original` e `coupon_code_normalized`;
- se a Nuvemshop rejeitar, não salva cupom local falso;
- bloqueia duplicidade por código normalizado;
- ao criar novo cupom ativo para o mesmo influencer, inativa o anterior.

Importância: garante que Orvox e Nuvemshop fiquem sincronizados.

---

## 4.6 `NuvemshopOrderSyncTest`

Cobre sincronização de pedidos simulando payloads reais:

### Pedido pendente

- pedido entra como `pending`;
- comissão fica `pending`;
- valor de comissão fica zero.

### Pedido pago

- pedido vira `paid`;
- cupom é associado ao influencer;
- itens são criados;
- comissão vira `forecasted`;
- base de comissão = subtotal - desconto;
- frete não entra na comissão.

### LGPD

- payload simulado inclui cliente, e-mail, telefone, documento e endereço;
- metadata salva pelo Orvox não guarda esses dados.

### Cancelamento antes do pagamento

- comissão pendente/prevista é cancelada.

### Reembolso após aprovação

- comissão aprovada vira `reversed`;
- cria ajuste negativo em `commission_adjustments`.

Importância: cobre as regras mais sensíveis do sistema.

---

## 4.7 `NuvemshopWebhookTest`

Cobre endpoint de webhook:

- `POST /api/webhooks/nuvemshop/{integration}` grava evento;
- salva headers/payload;
- dispara job `ProcessNuvemshopWebhookJob`;
- job processa payload de pedido e cria order/commission;
- eventos não mapeados ficam auditáveis.

Importância: valida que o webhook não perde eventos e deixa trilha para debug.

---

## 4.8 `InfluencerDashboardPrivacyTest`

Cobre LGPD no painel do influencer:

- influencer vê número do pedido;
- vê produto;
- vê comissão;
- não vê nome do cliente;
- não vê e-mail;
- não vê telefone;
- não vê documento;
- não vê endereço.

Importância: valida a regra de que influencer não acessa dados pessoais do comprador.

---

## 4.9 `GamificationServiceTest`

Cobre gamificação:

- usa a maior regra atingida;
- regras não acumulam;
- pedidos cancelados não contam;
- badge conquistada não duplica.

Importância: garante o comportamento esperado de bônus e badges.

---

## 4.10 `SettlementServiceTest`

Cobre fechamento mensal:

- fechamento usa comissões aprovadas do mês;
- aplica ajustes negativos;
- libera comissão para pagamento;
- cria item de fechamento por influencer;
- marca pagamento manual;
- cria `payment_records`;
- comissão vira `paid`.

Importância: valida o fluxo financeiro principal do MVP.

---

## 4.11 `NuvemshopProductAndWebhookRegistrationTest`

Cobre via mock HTTP:

- criação de produto de teste na Nuvemshop;
- exclusão de produto de teste;
- registro dos webhooks de pedido;
- valida que a URL de webhook é HTTPS.

Importância: valida o fluxo externo sem tocar na loja real.

---

---

## 4.12 `NuvemshopCouponUpdateDeleteContractTest`

Cobre os contratos de atualização e exclusão de cupom, quando os métodos já estiverem implementados:

- `updateCoupon()` envia `PUT` para a Nuvemshop e atualiza código/desconto local;
- `deleteCoupon()` envia `DELETE` para a Nuvemshop e marca o cupom local como `deleted`;
- se os métodos ainda não existirem, os testes ficam como `skipped`, servindo como checklist de implementação.

Importância: garante que edição/exclusão de cupons não fique apenas local e preserve histórico.

# 5. Testes reais contra Nuvemshop

Os testes reais ficam em:

```text
tests/Feature/Nuvemshop/NuvemshopRealSmokeTest.php
```

Eles só rodam se você definir:

```env
NUVEMSHOP_REAL_TESTS=true
NUVEMSHOP_REAL_STORE_ID=6228614
NUVEMSHOP_REAL_WEBHOOK_URL=https://SEU-NGROK.ngrok-free.app/api/webhooks/nuvemshop/1
```

Atenção: eles usam a integração real salva em `store_integrations`.

Rodar apenas estes testes:

```bash
./vendor/bin/sail test --group=nuvemshop-real
```

Ou:

```bash
./vendor/bin/sail test tests/Feature/Nuvemshop/NuvemshopRealSmokeTest.php
```

O teste real faz:

- lista cupons reais para validar token;
- cria produto de teste real;
- exclui produto real no `finally`;
- opcionalmente cadastra webhook real e remove no `finally`.

---

# 6. Fluxo E2E assistido com produto, cupom, compra e webhook

Como checkout/pagamento real depende da loja, frete e método de pagamento, a compra em si é um passo manual controlado. O comando prepara todo o cenário.

## 6.1 Preparar o cenário

Com Sail rodando e integração real ativa:

```bash
./vendor/bin/sail artisan orvox:test:nuvemshop-e2e \
  --coupon="ORVOXTESTE1" \
  --discount=1 \
  --product-price=1.00 \
  --webhook-url="https://SEU-NGROK.ngrok-free.app/api/webhooks/nuvemshop/1"
```

O comando cria:

- influencer local de teste;
- cupom real na Nuvemshop;
- produto real de teste na Nuvemshop;
- webhooks reais, se `--webhook-url` for informado;
- manifest em `storage/app/orvox-nuvemshop-e2e-manifest.json`.

Ele exibe:

- ID do influencer;
- ID do cupom;
- ID do produto;
- hint/URL do produto.

## 6.2 Fazer a compra manual

Abra a loja/produto e compre usando o cupom gerado.

Depois confirme se a Nuvemshop disparou webhook olhando:

```text
http://127.0.0.1:4040
```

E no Laravel:

```bash
./vendor/bin/sail artisan tinker
```

```php
\App\Models\WebhookEvent::latest()->take(10)->get(['event', 'external_id', 'status', 'created_at']);
```

## 6.3 Simular compra sem checkout

Para testar a lógica sem comprar de verdade:

```bash
./vendor/bin/sail artisan orvox:test:nuvemshop-e2e \
  --coupon="ORVOXTESTE2" \
  --discount=1 \
  --product-price=1.00 \
  --simulate-webhook
```

Isso cria localmente um pedido pago simulado, com cupom, produto e comissão.

## 6.4 Limpar tudo depois

```bash
./vendor/bin/sail artisan orvox:test:nuvemshop-cleanup
```

O cleanup tenta remover:

- produto real criado;
- cupom real criado;
- webhooks reais criados pelo comando;
- pedido simulado local;
- influencer local;
- usuário local.

Se quiser manter dados locais e limpar só a Nuvemshop:

```bash
./vendor/bin/sail artisan orvox:test:nuvemshop-cleanup --keep-local
```

---

# 7. Checklist antes de rodar E2E real

No `.env`:

```env
APP_URL=https://SEU-NGROK.ngrok-free.app
APP_PORT=8000
NUVEMSHOP_MOCK=false
NUVEMSHOP_API_BASE_URL=https://api.tiendanube.com/v1
NUVEMSHOP_USER_AGENT="Orvox Influencers MVP (seu-email@dominio.com)"
```

Limpar cache:

```bash
./vendor/bin/sail artisan optimize:clear
```

Validar integração:

```bash
./vendor/bin/sail artisan tinker
```

```php
$i = \App\Models\StoreIntegration::where('external_store_id', '6228614')->first();
[
    'id' => $i?->id,
    'external_store_id' => $i?->external_store_id,
    'has_token' => filled($i?->access_token),
    'scopes' => $i?->scopes,
    'status' => $i?->status?->value,
];
```

Precisa ter:

```text
external_store_id = 6228614
has_token = true
status = connected
scopes contém write_products, write_coupons, read_orders
```

---

# 8. Observações importantes

1. **Não cole token criptografado do MySQL no curl.** Pegue o token via Eloquent/Tinker:

```bash
./vendor/bin/sail artisan tinker --execute="
\$i = \App\Models\StoreIntegration::where('external_store_id', '6228614')->firstOrFail();
echo \$i->access_token.PHP_EOL;
"
```

2. **Webhooks reais precisam de HTTPS público.** Use ngrok ou Cloudflare Tunnel.

3. **Produto/cupom criados no E2E são reais.** O cleanup remove, mas em caso de erro confira no painel da Nuvemshop.

4. **A compra real não é 100% automatizada** porque checkout, frete e pagamento dependem da configuração da loja. O comando prepara o cenário, e a compra pode ser feita manualmente.

5. **Rode primeiro os testes mockados.** Eles são rápidos, seguros e não dependem da API externa.

---

# 9. Ordem recomendada

```bash
./vendor/bin/sail test tests/Unit
./vendor/bin/sail test tests/Feature/Nuvemshop
./vendor/bin/sail test tests/Feature/Webhooks
./vendor/bin/sail test tests/Feature/Influencer
./vendor/bin/sail test tests/Feature/Gamification
./vendor/bin/sail test tests/Feature/Settlements
```

Depois, com ngrok e integração real:

```bash
./vendor/bin/sail artisan orvox:test:nuvemshop-e2e --simulate-webhook
```

Depois, fluxo real com compra manual:

```bash
./vendor/bin/sail artisan orvox:test:nuvemshop-e2e \
  --coupon="ORVOXTESTE1" \
  --discount=1 \
  --product-price=1.00 \
  --webhook-url="https://SEU-NGROK.ngrok-free.app/api/webhooks/nuvemshop/1"
```

Ao final:

```bash
./vendor/bin/sail artisan orvox:test:nuvemshop-cleanup
```
