# Premiere Warehousing – Test Suite Documentation

This document describes the test suite setup, structure, and module-wise details for the Premiere Warehousing API backend.

---

## Table of Contents

1. [Setup & Prerequisites](#1-setup--prerequisites)
2. [Running Tests](#2-running-tests)
3. [Test Structure Overview](#3-test-structure-overview)
4. [Base Classes & Helpers](#4-base-classes--helpers)
5. [Shared Test Builders](#5-shared-test-builders)
6. [Authentication Patterns](#6-authentication-patterns)
7. [Module-Wise Test Details](#7-module-wise-test-details)

---

## 1. Setup & Prerequisites

### 1.1 Requirements

- **PHP** 8.2 or higher
- **Composer** (for dependencies)
- **MySQL** (for test database)
- **Laravel** 11.x

### 1.2 Installation Steps

```bash
# 1. Clone the repository and navigate to backend
cd PremiereWarehousingBackend

# 2. Install dependencies
composer install

# 3. Copy environment file
cp .env.example .env

# 4. Generate application key
php artisan key:generate

# 5. Generate JWT secret (required for auth tests)
php artisan jwt:secret
```

### 1.3 Test Database Setup

The test suite uses a **separate MySQL database** to avoid affecting development data.

**Step 1:** Create the test database in MySQL:

```sql
CREATE DATABASE test_premiere_warehousing CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
```

**Step 2:** Ensure your `.env` or MySQL config allows connection to this database. The test environment uses these values (from `phpunit.xml`):

- `DB_CONNECTION=mysql`
- `DB_DATABASE=test_premiere_warehousing`

**Step 3:** Run migrations on the test database:

```bash
php artisan migrate --env=testing
```

Or run tests once; `RefreshDatabase` will run migrations automatically.

### 1.4 Environment Variables Used in Tests

| Variable | Value | Purpose |
|---------|-------|---------|
| `APP_ENV` | testing | Laravel testing mode |
| `DB_DATABASE` | test_premiere_warehousing | Isolated test database |
| `BCRYPT_ROUNDS` | 4 | Faster password hashing in tests |
| `CACHE_STORE` | array | In-memory cache |
| `MAIL_MAILER` | array | No real emails sent |
| `QUEUE_CONNECTION` | sync | Jobs run synchronously |
| `BROADCAST_CONNECTION` | null | No WebSocket in tests |
| `AUDITING_ENABLED` | false | Disable audit logging |
| `JWT_SECRET` | test-jwt-secret-for-phpunit-min-32-chars | JWT for API auth |
| `SITETRAX_WEBHOOK_SECRET` | (empty) | Webhook accepts requests in tests |

### 1.5 Database Safety (Never Use Production)

Tests **never** use your main or staging database. A safety check in `TestCase` aborts if the configured database is:

- `premiere_warehousing` (main app DB)
- `audit_premiere_warehousing` (audit DB)

If you see an error like *"Tests cannot run against production database"*, fix your `.env.testing` or `phpunit.xml` to use a dedicated test database.

### 1.6 CI: SQLite In-Memory (`phpunit.ci.xml`)

**Staging and production CI** both use `phpunit.ci.xml` with SQLite in-memory – no MySQL or RDS needed:

| Environment | Config | Database |
|-------------|--------|----------|
| **Local** | `phpunit.xml` | MySQL (`test_premiere_warehousing`) |
| **CI (staging + production)** | `phpunit.ci.xml` | SQLite `:memory:` |

- **production.yml** runs: `php artisan test --configuration=phpunit.ci.xml`
- Same config for staging and production – no separate DB setup
- Requires `pdo_sqlite` PHP extension (included in setup-php action)

For local development with SQLite (if `php-sqlite3` is installed):

```bash
php artisan test --configuration=phpunit.ci.xml
```

---

## 2. Running Tests

### 2.1 Run All Tests

```bash
php artisan test
```

### 2.2 Run Specific Test Suites

```bash
# Unit tests only
php artisan test tests/Unit

# Feature tests only
php artisan test tests/Feature

# API tests only
php artisan test tests/Feature/Api
```

### 2.3 Run Specific Test File

```bash
php artisan test tests/Feature/Api/Invoices/InvoiceTest.php
```

### 2.4 Run Specific Test Method

```bash
php artisan test --filter=test_admin_can_create_invoice
```

### 2.5 Run Tests in Parallel (Faster)

```bash
php artisan test --parallel
```

### 2.6 Verbose Output

```bash
php artisan test --verbose
```

---

## 3. Test Structure Overview

```
tests/
├── TestCase.php                 # Base test class (RefreshDatabase, Mail/Storage/Queue fakes)
├── Unit/
│   └── ExampleTest.php         # Placeholder unit test
├── Feature/
│   ├── ExampleTest.php         # Basic health check
│   └── Api/
│       ├── ApiTestCase.php     # Base for all API tests (auth helpers, apiPrefix)
│       ├── Auth/               # Login, ForgotPassword, ResetPassword, etc.
│       ├── Carriers/
│       ├── Clients/
│       ├── Invoices/
│       ├── Schedules/
│       └── ...                 # Other API modules
└── Support/
    ├── ScheduleTestBuilder.php   # Shared schedule test data
    └── InvoiceTestBuilder.php     # Shared invoice test data
```

---

## 4. Base Classes & Helpers

### 4.1 TestCase (`tests/TestCase.php`)

- Uses `RefreshDatabase` – database is reset before each test
- `Mail::fake()` – no real emails
- `Storage::fake()` – no real file writes
- `Queue::fake()` – no real queue jobs

### 4.2 ApiTestCase (`tests/Feature/Api/ApiTestCase.php`)

Base class for all API feature tests. Provides:

| Method / Constant | Description |
|-------------------|-------------|
| `INVALID_ID` | Constant `999999` for not-found tests |
| `$apiPrefix` | `/api` – base path for API requests |
| `authHeaders(User $user)` | JWT Bearer + Accept headers |
| `authHeadersWithCompany(User, Company)` | Adds `company` header (required for admin CRUD) |
| `authHeadersWithCompanyAndLocation(User, Company, Location)` | Adds `company` + `location` (for manager-scoped) |
| `actingAsAdmin()` | Returns `['user', 'headers']` |
| `actingAsAdminWithCompany()` | Returns `['user', 'company', 'headers']` |
| `actingAsManager()` | Returns `['user', 'headers']` |
| `actingAsDriver()` | Returns `['user', 'headers']` |
| `apiPost($uri, $data, $headers)` | POST JSON request |
| `apiGet($uri, $headers)` | GET JSON request |
| `apiPut($uri, $data, $headers)` | PUT JSON request |
| `apiDelete($uri, $headers)` | DELETE JSON request |
| `assertApiSuccess($response)` | Asserts 200 + status: success |
| `assertApiValidationError($response, $errors)` | Asserts 422 + validation errors |

---

## 5. Shared Test Builders

### 5.1 ScheduleTestBuilder (`tests/Support/ScheduleTestBuilder.php`)

| Method | Returns | Use Case |
|--------|---------|----------|
| `createScheduleScenarioData(Company $company)` | company, client, location, carrier, trailer, yard_check, door | Base data without schedule |
| `createScheduleWithLocation(Company $company, ?string $invoicePrefix)` | Above + schedule | Admin/manager schedule tests |
| `createScheduleWithDriver(Company $company)` | Above + driver (attached to location) | Driver-scoped tests (offline sync, time tracking) |

**Usage:** `use Tests\Support\ScheduleTestBuilder;` and `use ScheduleTestBuilder;` in your test class.

### 5.2 InvoiceTestBuilder (`tests/Support/InvoiceTestBuilder.php`)

| Method | Returns | Use Case |
|--------|---------|----------|
| `createInvoiceWithServiceItem(Company $company, ?string $invoicePrefix)` | invoice, invoice_item, company, schedule, location, carrier | Credit memo, invoice payments, CSV upload tests |

**Usage:** `use Tests\Support\InvoiceTestBuilder;` and `use InvoiceTestBuilder;` in your test class. Uses `ScheduleTestBuilder` internally.

---

## 6. Authentication Patterns

### 6.1 Admin Tests

Most admin endpoints require `company` header:

```php
$company = Company::factory()->create();
$user = User::factory()->role('admin')->create();

$response = $this->withHeaders($this->authHeadersWithCompany($user, $company))
    ->getJson($this->apiPrefix . '/invoices');
```

### 6.2 Manager Tests

Some endpoints require `location` header:

```php
$company = Company::factory()->create();
$location = Location::factory()->create(['company_id' => $company->id]);
$manager = User::factory()->role('manager')->create();
$location->users()->attach($manager->id);

$response = $this->withHeaders($this->authHeadersWithCompanyAndLocation($manager, $company, $location))
    ->getJson($this->apiPrefix . '/schedules?locationid=' . $location->id);
```

### 6.3 Driver Tests

Drivers must be attached to a location:

```php
$data = $this->createScheduleWithDriver($company);
$driver = $data['driver'];

$response = $this->withHeaders($this->authHeadersWithCompany($driver, $company))
    ->postJson($this->apiPrefix . "/schedules/{$data['schedule']->id}/log-time", ['type' => 'in']);
```

### 6.4 Unauthenticated Tests

```php
$response = $this->getJson($this->apiPrefix . '/invoices');
$response->assertStatus(403);
```

---

## 7. Module-Wise Test Details

### 7.1 Auth

| File | Tests | Description |
|------|-------|-------------|
| **LoginTest** | 17 tests | Login success/failure per role, validation (email, password, type), data providers for invalid type |
| **ForgotPasswordTest** | 5 tests | Forgot password flow, validation |
| **ResetPasswordTest** | 5 tests | Reset with token, validation |
| **CreatePasswordTest** | 5 tests | Create password with invite token |
| **MobileAuthTest** | 8 tests | Mobile OTP forgot/verify/reset password |
| **ProtectedAuthTest** | 8 tests | Get/update user details, delete profile image |
| **VerifyLocationPasscodeTest** | 5 tests | Location passcode verification (public) |

### 7.2 Carriers

| File | Tests | Description |
|------|-------|-------------|
| **CarrierTest** | 12 tests | CRUD, validation (required fields, carrier_type via data provider), cross-company isolation, auth required |

**Data Provider:** `invalidCarrierTypeProvider` – invalid, empty, numeric, air

### 7.3 Clients

| File | Tests | Description |
|------|-------|-------------|
| **ClientTest** | 12 tests | CRUD, validation (required, general_ledger format via data provider), not-found, cross-company isolation |

**Data Provider:** `invalidGeneralLedgerCodeProvider` – invalid, too short, wrong format

### 7.4 Companies

| File | Tests | Description |
|------|-------|-------------|
| **CompanyTest** | 9 tests | CRUD, validation (required, unique name), unauthenticated |

### 7.5 Configuration

| File | Tests | Description |
|------|-------|-------------|
| **ConfigurationTest** | 4 tests | List, update, validation, admin-only |

### 7.6 Client Templates

| File | Tests | Description |
|------|-------|-------------|
| **ClientTemplateTest** | 7 tests | CRUD for templates (nested under clients), validation, admin-only |

### 7.7 Dashboard

| File | Tests | Description |
|------|-------|-------------|
| **DashboardTest** | 3 tests | Get statistics (admin, with location filter), unauthenticated |

### 7.8 Dropdowns

| File | Tests | Description |
|------|-------|-------------|
| **DropdownTest** | 5 tests | Trailers list, carriers list, doors list, trailers with location filter, unauthenticated |

### 7.9 Equipments

| File | Tests | Description |
|------|-------|-------------|
| **EquipmentTest** | 8 tests | CRUD, create for all locations, validation, unauthenticated |

### 7.10 Invoices

| File | Tests | Description |
|------|-------|-------------|
| **InvoiceTest** | 24 tests | CRUD, generate ID, counts, filter options, products/services/equipment, save products, payments, credit memos, export, download, completed steps, not-found, admin-only |

### 7.11 Invoice Credit Memos

| File | Tests | Description |
|------|-------|-------------|
| **InvoiceCreditMemoTest** | 7 tests | Create credit memo, get details, change status, validation, not-found, admin-only |

**Uses:** `InvoiceTestBuilder`

### 7.12 Invoice Payments

| File | Tests | Description |
|------|-------|-------------|
| **InvoicePaymentTest** | 11 tests | Save paid details, CSV upload, validation (invoice number, field, columns, rows), admin-only |

**Uses:** `InvoiceTestBuilder`

### 7.13 Location Default Charges

| File | Tests | Description |
|------|-------|-------------|
| **LocationDefaultChargesTest** | 8 tests | CRUD for default services/equipments, validation (operation_type), unauthenticated |

### 7.14 Location Doors

| File | Tests | Description |
|------|-------|-------------|
| **LocationDoorTest** | 7 tests | Get doors, dropdown, save, update, validation, unauthenticated, multiple location doors |

### 7.15 Location Entrance (Public)

| File | Tests | Description |
|------|-------|-------------|
| **LocationEntranceTest** | 6 tests | Create trailer (QR scan), out trailer, validation – no auth required |

### 7.16 Location Services

| File | Tests | Description |
|------|-------|-------------|
| **LocationServiceTest** | 9 tests | CRUD, validation, change model default pricing, unauthenticated |

### 7.17 Locations

| File | Tests | Description |
|------|-------|-------------|
| **LocationTest** | 8 tests | CRUD, validation (required, passcode digits), unauthenticated |

### 7.18 Mobile (Driver)

| File | Tests | Description |
|------|-------|-------------|
| **MobileTest** | 10 tests | Save device token, force update version, validation (device_type via data provider), driver-only |

**Data Provider:** `invalidDeviceTypeProvider` – windows, linux, invalid

### 7.19 Offline Sync (Driver)

| File | Tests | Description |
|------|-------|-------------|
| **OfflineSyncTest** | 6 tests | Sync comments, log times, validation (required, structure), not-found, driver-only |

**Uses:** `ScheduleTestBuilder` (createScheduleWithDriver)

### 7.20 Report Config

| File | Tests | Description |
|------|-------|-------------|
| **ReportConfigTest** | 3 tests | Manager/admin can get config, unauthenticated |

### 7.21 Reports

| File | Tests | Description |
|------|-------|-------------|
| **ReportTest** | 15 tests | CRUD (except update), show by slug, generate, change status, create with schedule, validation, manager scope, admin/manager only |

### 7.22 Report Schedules

| File | Tests | Description |
|------|-------|-------------|
| **ReportScheduleTest** | 4 tests | List schedules, get all, admin/manager, unauthenticated |

### 7.23 Schedules

| File | Tests | Description |
|------|-------|-------------|
| **ScheduleTest** | 16 tests | CRUD, update-by-values, change display order, edit extra info, validation (required, schedule_type via data provider), not-found, manager-scope isolation |

**Uses:** `ScheduleTestBuilder`  
**Data Provider:** `invalidScheduleTypeProvider` – invalid, both, numeric

### 7.24 Schedule Time Tracking (Driver)

| File | Tests | Description |
|------|-------|-------------|
| **ScheduleTimeTrackingTest** | 12 tests | Log in/out/completed/parked, door required for in, validation (type via data provider), lat/long for parked, not-found, driver-only |

**Uses:** `ScheduleTestBuilder` (createScheduleWithDriver)  
**Data Provider:** `invalidLogTimeTypeProvider` – invalid, typo in, typo out, numeric

### 7.25 Services

| File | Tests | Description |
|------|-------|-------------|
| **ServiceTest** | 7 tests | CRUD, validation, change model default pricing, unauthenticated |

### 7.26 Services & Equipments

| File | Tests | Description |
|------|-------|-------------|
| **ServicesAndEquipmentsTest** | 9 tests | Add/delete service and equipment to schedule, get services/equipments, validation, unauthenticated |

**Uses:** `ScheduleTestBuilder` (createScheduleWithLocation)

### 7.27 Common Stats

| File | Tests | Description |
|------|-------|-------------|
| **CommonStatsTest** | 3 tests | Sidebar stats (manager, admin), unauthenticated |

### 7.28 Teams

| File | Tests | Description |
|------|-------|-------------|
| **TeamTest** | 12 tests | CRUD, create admin/manager, validation (required, role, location for manager), resend invite, unauthenticated |

### 7.29 Trailers

| File | Tests | Description |
|------|-------|-------------|
| **TrailerTest** | 8 tests | CRUD, generate yard check from yesterday, fetch store trailer details, validation, unauthenticated |

### 7.30 Webhooks

| File | Tests | Description |
|------|-------|-------------|
| **SiteTraxWebhookTest** | 4 tests | Valid payload, empty payload, array of records, secret validation – no auth |

### 7.31 Yard Check

| File | Tests | Description |
|------|-------|-------------|
| **YardCheckTest** | 4 tests | Change status, invalid trailer, unauthenticated, yard check map data |

---

## 8. Data Providers

Tests using PHP 8 `#[DataProvider]` attribute for multiple validation scenarios:

| Test File | Provider | Invalid Values |
|-----------|----------|----------------|
| CarrierTest | invalidCarrierTypeProvider | invalid, empty, numeric, air |
| ClientTest | invalidGeneralLedgerCodeProvider | invalid, too short, wrong format |
| ScheduleTest | invalidScheduleTypeProvider | invalid, both, numeric |
| ScheduleTimeTrackingTest | invalidLogTimeTypeProvider | invalid, typo in, typo out, numeric |
| MobileTest | invalidDeviceTypeProvider | windows, linux, invalid |
| LoginTest | invalidLoginTypeProvider | invalid, superadmin, numeric, empty |

---

## 9. Quick Reference

| Command | Description |
|---------|-------------|
| `php artisan test` | Run all tests (local, MySQL) |
| `php artisan test --configuration=phpunit.ci.xml` | Run with SQLite (CI or local) |
| `php artisan test tests/Feature/Api/Invoices/InvoiceTest.php` | Run one file |
| `php artisan test --filter=test_admin_can_create` | Run matching tests |
| `php artisan test --parallel` | Run in parallel |

| Test Count | ~310 tests |
| Assertions | ~923 |
| Duration | ~40–45 seconds |

---

## 10. Troubleshooting

### "Tests cannot run against production database"

Your `.env.testing` or environment is pointing to a production DB. Use `test_premiere_warehousing` or SQLite `:memory:` instead. See [1.5 Database Safety](#15-database-safety-never-use-production).

### Database connection errors

- **Local (MySQL):** Ensure `test_premiere_warehousing` database exists; run `php artisan migrate --env=testing`
- **CI (SQLite):** Uses `phpunit.ci.xml` – no DB setup. Ensure `pdo_sqlite` is available (setup-php adds it).

### "could not find driver" (SQLite)

When running `php artisan test --configuration=phpunit.ci.xml` locally: install `php-sqlite3` or use `php artisan test` (MySQL) instead.

### JWT errors

- Ensure `JWT_SECRET` is set in phpunit (or .env.testing)
- Run `php artisan jwt:secret` if needed

### Slow tests

- Use `php artisan test --parallel` (with proper DB setup)
- Check `BCRYPT_ROUNDS=4` in phpunit.xml

### Factory/Model errors

- Ensure all factories exist in `database/factories/`
- Run `composer dump-autoload` after adding new files
