# Testing

## Framework

Pest PHP. Never use PHPUnit test classes directly — always Pest syntax.

## Test structure

```
tests/
├── Feature/
│   ├── Scoring/AlertScoringServiceTest.php
│   ├── Notifications/NotificationDispatchTest.php
│   ├── Payments/SubscriptionTest.php
│   └── Livewire/DashboardTest.php
└── Unit/
    ├── Services/FuelPriceServiceTest.php
    └── Services/StationTaggingServiceTest.php
```

## Conventions

- Use `RefreshDatabase` trait on Feature tests
- Factory-first: all test data via Eloquent factories — never raw DB inserts
- Mock external APIs (Fuel Finder, Vonage, OneSignal, FRED) — never hit live APIs in tests
- Use `Http::fake()` for all outbound HTTP in tests
- Stripe: use Cashier's built-in test helpers, never hit Stripe API in tests

## What to test

- AlertScoringService: all signal combinations, confidence thresholds, no_signal cases
- NotificationDispatchService: correct channels returned per tier
- SubscriptionService: tier detection, SMS limit counting
- Livewire components: use `Livewire::test()` for interaction testing
- Stripe webhooks: test `customer.subscription.deleted` downgrades user correctly

## Running tests

```bash
php artisan test              # Full suite
php artisan test --filter=Scoring  # Single test class
php artisan test --parallel   # Parallel (faster)
```

---
paths:
  - "tests/**/*.php"
---
