# TenantPilot Testing Guidelines

Status: 2026-05-15
Applies to: Pest 4.3+, PHPUnit 12, Laravel 12, Filament 5, Livewire 4.

## Test Philosophy

Tests protect business truth: workspace isolation, tenant isolation, RBAC, auditability, immutable snapshots, restore safety, queued operation correctness, and Graph contract safety.

Do not create broad tests for thin presentation helpers unless the helper encodes operator-critical behavior.

## Test Pyramid

| Layer | Use for | Default lane |
|---|---|---|
| Unit | Pure services, value objects, mappers, policy helpers | fast-feedback |
| Feature | HTTP, DB, policies, queued jobs, audit side effects | fast-feedback/confidence |
| Filament/Livewire | Pages, widgets, relation managers, actions | confidence |
| PostgreSQL | migrations, JSONB, partial indexes, locks, FK isolation | pgsql |
| Browser | critical multi-step UI, JS smoke, visual/user workflow checks | browser |
| Heavy governance | broad surface discovery and drift checks | heavy-governance |

## Minimum Standard for New Features

- Every new policy gets allowed and denied tests.
- Every new destructive/high-impact Filament action gets action tests.
- Every new tenant-owned model gets cross-tenant isolation tests.
- Every new migration touching constraints/indexes gets PostgreSQL lane coverage when SQLite cannot prove the behavior.
- Every job that calls Graph is tested for idempotency, terminal-state handling, retry/throttle classification, and safe logging.
- Every feature spec states test impact and lane classification.

## Critical User Journeys to Keep Covered

- Workspace selection and tenant selection.
- Provider connection create/verify/disable/health-check.
- Policy sync, snapshot capture, version history, diff navigation.
- Backup set creation, add policies, schedule run/retry.
- Restore preview, confirmation, execution, partial failure handling.
- Finding triage, assignment, exception, evidence review.
- Audit log visibility and tenant-scope enforcement.
- System panel login/session isolation and platform capability checks.

## Filament Action Test Pattern

```php
use App\Filament\Resources\BackupScheduleResource\Pages\ListBackupSchedules;
use App\Jobs\RunBackupScheduleJob;
use Illuminate\Support\Facades\Bus;
use function Pest\Livewire\livewire;

it('queues a backup schedule run for an authorized tenant member', function () {
    Bus::fake();

    [$user, $tenant, $schedule] = tenantUserWithBackupScheduleRunCapability();

    actingAs($user);
    Filament::setTenant($tenant);

    livewire(ListBackupSchedules::class)
        ->assertTableActionVisible('runNow', $schedule)
        ->callTableAction('runNow', $schedule);

    Bus::assertDispatched(RunBackupScheduleJob::class);

    expectAuditLogged('backup_schedule.run_requested', $schedule);
});
```

## Policy Test Pattern

```php
it('hides another workspace backup set as not found', function () {
    [$actor, $ownWorkspace] = workspaceMember();
    $foreignBackupSet = BackupSet::factory()->forWorkspace()->create();

    $response = Gate::forUser($actor)->inspect('view', $foreignBackupSet);

    expect($response->denied())->toBeTrue()
        ->and($response->status())->toBe(404);
});
```

## PostgreSQL Lane Rule

Use `cd apps/platform && ./vendor/bin/sail php vendor/bin/pest -c phpunit.pgsql.xml` or the equivalent CI PostgreSQL lane for:

- JSONB migrations and GIN indexes.
- Partial unique indexes.
- Composite foreign keys.
- `lockForUpdate()` behavior.
- Tenant/workspace constraint migrations.
- Query plans where performance depends on PostgreSQL-specific operators.

## CI Recommendation

Release/confidence CI should run:

1. `composer validate --strict`
2. `composer audit`
3. `corepack pnpm audit --audit-level moderate`
4. `./vendor/bin/pint --test`
5. `composer run test`
6. `composer run test:pgsql` when database paths changed
7. `composer run test:browser` for UI workflow changes
8. `corepack pnpm build:platform`

## Fragility Controls

- Prefer factories with explicit state over global seed assumptions.
- Keep full workspace/tenant/member setup opt-in.
- Assert outcomes, audit events, and authorization behavior, not implementation details.
- Use fake Graph clients that fail hard if UI rendering accidentally calls Graph.
- Avoid snapshot tests for volatile admin markup unless visual regression is the real goal.
