TenantAtlas/tests/Feature/Operations/TenantlessOperationRunViewerTest.php
Ahmed Darrazi ab0ffff1d1 feat(onboarding): enterprise wizard + tenantless run viewer
- Canonical /admin/onboarding entry point; legacy routes 404\n- Tenantless run viewer at /admin/operations/{run} with membership-based 404\n- RBAC UX (disabled controls + tooltips) and server-side 403\n- DB-only rendering/refresh; contract registry enforced\n- Adds migrations + tests + spec artifacts
2026-02-04 23:00:06 +01:00

102 lines
3.3 KiB
PHP

<?php
declare(strict_types=1);
use App\Models\OperationRun;
use App\Models\User;
use App\Models\Workspace;
use App\Models\WorkspaceMembership;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\Workspaces\WorkspaceContext;
it('allows viewing an operation run without a selected workspace when the user is a member of the run workspace', function (): void {
$workspace = Workspace::factory()->create();
$user = User::factory()->create();
WorkspaceMembership::factory()->create([
'workspace_id' => (int) $workspace->getKey(),
'user_id' => (int) $user->getKey(),
'role' => 'owner',
]);
session()->forget(WorkspaceContext::SESSION_KEY);
$run = OperationRun::factory()->create([
'workspace_id' => (int) $workspace->getKey(),
'tenant_id' => null,
'type' => 'provider.connection.check',
'status' => OperationRunStatus::Queued->value,
'outcome' => OperationRunOutcome::Pending->value,
]);
$this->actingAs($user)
->get("/admin/operations/{$run->getKey()}")
->assertSuccessful();
expect(session()->get(WorkspaceContext::SESSION_KEY))->toBeNull();
});
it('returns 404 for non-members when viewing an operation run without a selected workspace', function (): void {
$workspace = Workspace::factory()->create();
$user = User::factory()->create();
session()->forget(WorkspaceContext::SESSION_KEY);
$run = OperationRun::factory()->create([
'workspace_id' => (int) $workspace->getKey(),
'tenant_id' => null,
'type' => 'provider.connection.check',
'status' => OperationRunStatus::Queued->value,
'outcome' => OperationRunOutcome::Pending->value,
]);
$this->actingAs($user)
->get("/admin/operations/{$run->getKey()}")
->assertNotFound();
});
it('renders stored target scope and failure details for a completed run', function (): void {
$workspace = Workspace::factory()->create();
$user = User::factory()->create();
WorkspaceMembership::factory()->create([
'workspace_id' => (int) $workspace->getKey(),
'user_id' => (int) $user->getKey(),
'role' => 'owner',
]);
session()->forget(WorkspaceContext::SESSION_KEY);
$entraTenantId = '11111111-1111-1111-1111-111111111111';
$failureMessage = 'Missing required Graph permissions.';
$run = OperationRun::factory()->create([
'workspace_id' => (int) $workspace->getKey(),
'tenant_id' => null,
'type' => 'provider.connection.check',
'status' => OperationRunStatus::Completed->value,
'outcome' => OperationRunOutcome::Failed->value,
'context' => [
'target_scope' => [
'entra_tenant_id' => $entraTenantId,
'entra_tenant_name' => 'Contoso',
],
],
'failure_summary' => [
[
'code' => 'provider.connection.check.failed',
'reason_code' => 'permission_denied',
'message' => $failureMessage,
],
],
]);
$this->actingAs($user)
->get("/admin/operations/{$run->getKey()}")
->assertSuccessful()
->assertSee($entraTenantId)
->assertSee('permission_denied')
->assertSee($failureMessage);
});