# 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" ---