TenantAtlas/apps/platform/tests/Feature/Baselines/BaselineCompareMatrixCompareAllActionTest.php
ahmido eca19819d1 feat: add workspace baseline compare matrix (#221)
## Summary
- add a workspace-scoped baseline compare matrix page under baseline profiles
- derive matrix tenant summaries, subject rows, cell states, freshness, and trust from existing snapshots, compare runs, and findings
- add confirmation-gated `Compare assigned tenants` actions on the baseline detail and matrix surfaces without introducing a workspace umbrella run
- preserve matrix navigation context into tenant compare and finding drilldowns and add centralized matrix badge semantics
- include spec, plan, data model, contracts, quickstart, tasks, and focused feature/browser coverage for Spec 190

## Verification
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Badges/BaselineCompareMatrixBadgesTest.php tests/Feature/Baselines/BaselineCompareMatrixBuilderTest.php tests/Feature/Baselines/BaselineCompareMatrixCompareAllActionTest.php tests/Feature/Baselines/BaselineComparePerformanceGuardTest.php tests/Feature/Filament/BaselineCompareMatrixPageTest.php tests/Feature/Filament/BaselineProfileCompareStartSurfaceTest.php tests/Feature/Rbac/BaselineCompareMatrixAuthorizationTest.php tests/Feature/Guards/ActionSurfaceContractTest.php tests/Feature/Guards/NoAdHocStatusBadgesTest.php tests/Feature/Guards/NoDiagnosticWarningBadgesTest.php`
- `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
- completed an integrated-browser smoke flow locally for matrix render, differ filter, finding drilldown round-trip, and `Compare assigned tenants` confirmation/action

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #221
2026-04-11 10:20:25 +00:00

96 lines
3.8 KiB
PHP

<?php
declare(strict_types=1);
use App\Filament\Pages\BaselineCompareMatrix;
use App\Jobs\CompareBaselineToTenantJob;
use App\Models\OperationRun;
use App\Models\Tenant;
use App\Services\Baselines\BaselineCompareService;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Queue;
use Livewire\Livewire;
use Tests\Feature\Concerns\BuildsBaselineCompareMatrixFixtures;
uses(RefreshDatabase::class, BuildsBaselineCompareMatrixFixtures::class);
it('fans out compare starts across the visible assigned set without creating a workspace umbrella run', function (): void {
Queue::fake();
$fixture = $this->makeBaselineCompareMatrixFixture();
$readonlyTenant = Tenant::factory()->create([
'workspace_id' => (int) $fixture['workspace']->getKey(),
'name' => 'Readonly Contoso',
]);
$fixture['user']->tenants()->syncWithoutDetaching([
(int) $readonlyTenant->getKey() => ['role' => 'readonly'],
]);
$this->assignTenantToBaselineProfile($fixture['profile'], $readonlyTenant);
$service = app(BaselineCompareService::class);
$existingRunResult = $service->startCompareForProfile(
$fixture['profile'],
$fixture['visibleTenantTwo'],
$fixture['user'],
);
expect($existingRunResult['ok'] ?? false)->toBeTrue();
$result = $service->startCompareForVisibleAssignments($fixture['profile'], $fixture['user']);
expect($result['visibleAssignedTenantCount'])->toBe(3)
->and($result['queuedCount'])->toBe(1)
->and($result['alreadyQueuedCount'])->toBe(1)
->and($result['blockedCount'])->toBe(1);
$launchStates = collect($result['targets'])
->mapWithKeys(static fn (array $target): array => [(int) $target['tenantId'] => (string) $target['launchState']])
->all();
expect($launchStates[(int) $fixture['visibleTenant']->getKey()] ?? null)->toBe('queued')
->and($launchStates[(int) $fixture['visibleTenantTwo']->getKey()] ?? null)->toBe('already_queued')
->and($launchStates[(int) $readonlyTenant->getKey()] ?? null)->toBe('blocked');
Queue::assertPushed(CompareBaselineToTenantJob::class);
$activeRuns = OperationRun::query()
->where('workspace_id', (int) $fixture['workspace']->getKey())
->where('type', 'baseline_compare')
->get();
expect($activeRuns)->toHaveCount(2)
->and($activeRuns->every(static fn (OperationRun $run): bool => $run->tenant_id !== null))->toBeTrue()
->and($activeRuns->every(static fn (OperationRun $run): bool => (string) $run->status === OperationRunStatus::Queued->value))->toBeTrue()
->and($activeRuns->every(static fn (OperationRun $run): bool => (string) $run->outcome === OperationRunOutcome::Pending->value))->toBeTrue()
->and(OperationRun::query()->whereNull('tenant_id')->where('type', 'baseline_compare')->count())->toBe(0);
});
it('runs compare assigned tenants from the matrix page and keeps feedback on tenant-owned runs', function (): void {
Queue::fake();
$fixture = $this->makeBaselineCompareMatrixFixture();
$this->setAdminWorkspaceContext($fixture['user'], $fixture['workspace']);
Livewire::actingAs($fixture['user'])
->test(BaselineCompareMatrix::class, ['record' => $fixture['profile']->getKey()])
->assertActionVisible('compareAssignedTenants')
->assertActionEnabled('compareAssignedTenants')
->callAction('compareAssignedTenants')
->assertStatus(200);
Queue::assertPushed(CompareBaselineToTenantJob::class, 2);
expect(OperationRun::query()
->where('workspace_id', (int) $fixture['workspace']->getKey())
->where('type', 'baseline_compare')
->whereNull('tenant_id')
->count())->toBe(0);
});