TenantAtlas/apps/platform/tests/Feature/Filament/Spec398DecisionPageContractMigrationTest.php
ahmido 6da925bd52 feat: migrate decision page contracts to productized flow (#469)
Automated PR provided by Codex via Gitea API.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #469
2026-06-22 18:16:05 +00:00

240 lines
9.4 KiB
PHP

<?php
declare(strict_types=1);
use App\Filament\Resources\RestoreRunResource;
use App\Filament\Resources\RestoreRunResource\Pages\CreateRestoreRun;
use App\Models\BackupItem;
use App\Models\BackupSet;
use App\Models\Finding;
use App\Models\ManagedEnvironment;
use App\Models\Policy;
use App\Support\Baselines\BaselineCompareReasonCode;
use App\Support\OperationRunType;
use App\Support\RestoreSafety\RestoreSafetyResolver;
use Livewire\Livewire;
it('renders baseline compare idle state with only the decision-card compare action visible', function (): void {
[$user, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'manager');
seedActiveBaselineForTenant($environment);
createInventorySyncOperationRunWithCoverage($environment, ['deviceConfiguration' => 'succeeded']);
$this->actingAs($user);
setAdminPanelContext($environment);
$component = baselineCompareLandingLivewire($environment)
->assertSee('Which baseline drift requires action?')
->assertSee('Needs attention')
->assertSee('Compare now')
->assertActionEnabled('compareNow')
->assertDontSee('OperationRun proof')
->assertDontSee('raw payload')
->assertDontSee('provider response');
expect(substr_count($component->html(), 'data-testid="baseline-compare-primary-action"'))->toBe(1);
});
it('renders baseline compare as one decision with technical proof collapsed', function (): void {
[$user, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'manager');
[$profile, $snapshot] = seedActiveBaselineForTenant($environment);
$run = seedBaselineCompareRun($environment, $profile, $snapshot, [
'reason_code' => BaselineCompareReasonCode::OverdueFindingsRemain->value,
'coverage' => [
'effective_types' => ['deviceConfiguration'],
'covered_types' => ['deviceConfiguration'],
'uncovered_types' => [],
'proof' => true,
],
]);
Finding::factory()->create([
'managed_environment_id' => (int) $environment->getKey(),
'workspace_id' => (int) $environment->workspace_id,
'finding_type' => Finding::FINDING_TYPE_DRIFT,
'scope_key' => 'baseline_profile:'.$profile->getKey(),
'severity' => Finding::SEVERITY_HIGH,
'status' => Finding::STATUS_NEW,
'source' => OperationRunType::BaselineCompare->value,
'baseline_operation_run_id' => (int) $run->getKey(),
]);
$this->actingAs($user);
setAdminPanelContext($environment);
$component = baselineCompareLandingLivewire($environment)
->assertSee('Which baseline drift requires action?')
->assertSee('Needs attention')
->assertSee('Review drift findings')
->assertSee('Technical details and audit links')
->assertSee('View compare readiness details')
->assertDontSee('OperationRun proof')
->assertDontSee('raw diff')
->assertDontSee('raw payload')
->assertDontSee('provider response');
$html = $component->html();
expect($html)
->not->toContain('data-testid="baseline-compare-technical-details" open')
->not->toContain('data-testid="baseline-compare-readiness-disclosure" open')
->not->toContain('data-testid="baseline-compare-diagnostics" open');
});
it('renders restore source decision without duplicate readiness status vocabulary', function (): void {
[$user, $tenant, $backupSet] = spec398RestorePreviewFixture();
setAdminPanelContext($tenant);
Livewire::actingAs($user)
->test(CreateRestoreRun::class)
->fillForm(['backup_set_id' => (int) $backupSet->getKey()])
->assertSee('Is this restore safe to continue?')
->assertSee('Needs attention')
->assertSee('Primary next action')
->assertSee('Continue to scope.')
->assertSee('Backup quality summary')
->assertSee('Ready')
->assertSee('View safety gates and proof')
->assertDontSee('Restore readiness')
->assertDontSee('Restore needs preparation.')
->assertDontSee('Ready for final confirmation.')
->assertDontSee("Restore can't continue yet.")
->assertDontSee('Degraded input')
->assertDontSee('Operation proof is complete');
});
it('renders restore preview with capped rows and secondary proof collapsed', function (): void {
[$user, $tenant, $backupSet, $backupItem] = spec398RestorePreviewFixture();
$data = spec398RestorePreviewData($backupSet, $backupItem);
setAdminPanelContext($tenant);
$component = Livewire::actingAs($user)
->test(CreateRestoreRun::class)
->set('data', $data)
->goToWizardStep(4)
->assertWizardCurrentStep(4)
->assertSee('Preview evidence')
->assertSee('Policies changed')
->assertSee('Requires review')
->assertSee('Validation blockers')
->assertSee('Next gate')
->assertSee('View secondary preview counts')
->assertSee('View safety gates and restore proof')
->assertSee('Spec398 Changed Policy 8')
->assertDontSee('Spec398 Changed Policy 9')
->assertDontSee('spec398 raw restore payload')
->assertDontSee('provider response payload');
$html = $component->html();
expect($html)
->toContain('data-testid="restore-run-preview-primary-metrics"')
->toContain('data-testid="restore-run-preview-secondary-metrics"')
->toContain('4 additional changed policies kept in detailed review.')
->not->toContain('data-testid="restore-run-preview-secondary-metrics" open')
->not->toContain('data-testid="restore-run-preview-evidence" open');
});
function spec398RestorePreviewFixture(): array
{
$tenant = ManagedEnvironment::factory()->create([
'rbac_status' => 'ok',
'rbac_last_checked_at' => now(),
]);
[$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');
ensureDefaultProviderConnection($tenant, 'microsoft');
$policy = Policy::create([
'managed_environment_id' => (int) $tenant->getKey(),
'external_id' => 'spec398-policy',
'policy_type' => 'deviceConfiguration',
'display_name' => 'Spec398 Restore Policy',
'platform' => 'windows',
]);
$backupSet = BackupSet::factory()->create([
'managed_environment_id' => (int) $tenant->getKey(),
'name' => 'Spec398 Restore Backup',
'status' => 'completed',
'item_count' => 1,
]);
$backupItem = BackupItem::factory()->create([
'managed_environment_id' => (int) $tenant->getKey(),
'backup_set_id' => (int) $backupSet->getKey(),
'policy_id' => (int) $policy->getKey(),
'policy_identifier' => $policy->external_id,
'policy_type' => $policy->policy_type,
'platform' => $policy->platform,
'payload' => [
'id' => $policy->external_id,
'displayName' => $policy->display_name,
'settings' => ['encryption' => 'required'],
],
'metadata' => [
'displayName' => $policy->display_name,
],
'assignments' => [],
]);
return [$user, $tenant, $backupSet, $backupItem];
}
function spec398RestorePreviewData(BackupSet $backupSet, BackupItem $backupItem): array
{
/** @var RestoreSafetyResolver $resolver */
$resolver = app(RestoreSafetyResolver::class);
$previewDiffs = collect(range(1, 12))
->map(fn (int $index): array => [
'policy_identifier' => 'spec398-policy-'.$index,
'display_name' => 'Spec398 Changed Policy '.$index,
'policy_type' => 'deviceConfiguration',
'platform' => 'windows',
'action' => 'update',
'assignments_changed' => $index === 1,
'scope_tags_changed' => false,
'review_reason' => 'Spec398 preview change requires review.',
'review_action_label' => 'Review change',
'diff' => [
'summary' => ['added' => 0, 'removed' => 0, 'changed' => 1],
'changed' => ['setting' => ['before' => 'off', 'after' => 'on']],
'added' => [],
'removed' => [],
],
])
->all();
$data = [
'backup_set_id' => (int) $backupSet->getKey(),
'scope_mode' => 'selected',
'backup_item_ids' => [(int) $backupItem->getKey()],
'is_dry_run' => true,
'group_mapping' => [],
'check_summary' => ['blocking' => 0, 'warning' => 1, 'safe' => 2],
'check_results' => [
['code' => 'warning', 'severity' => 'warning', 'message' => 'Review assignment changes before execution.'],
['code' => 'safe', 'severity' => 'safe', 'message' => 'Scope fingerprint is current.'],
],
'checks_ran_at' => now('UTC')->toIso8601String(),
'preview_summary' => [
'generated_at' => now('UTC')->toIso8601String(),
'policies_total' => 12,
'policies_changed' => 12,
'assignments_changed' => 1,
'scope_tags_changed' => 0,
'raw_payload_marker' => 'spec398 raw restore payload',
'provider_response' => 'provider response payload',
],
'preview_diffs' => $previewDiffs,
'preview_ran_at' => now('UTC')->toIso8601String(),
];
$data['check_basis'] = $resolver->checksBasisFromData($data);
$data['preview_basis'] = $resolver->previewBasisFromData($data);
return RestoreRunResource::synchronizeRestoreSafetyDraft($data);
}