create(['name' => 'Alpha Tenant']); [$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'readonly'); $tenantB = Tenant::factory()->create([ 'workspace_id' => (int) $tenantA->workspace_id, 'name' => 'Beta Tenant', ]); createUserWithTenant(tenant: $tenantB, user: $user, role: 'readonly'); $tenantDenied = Tenant::factory()->create([ 'workspace_id' => (int) $tenantA->workspace_id, 'name' => 'Denied Tenant', ]); $otherOwner = User::factory()->create(); createUserWithTenant(tenant: $tenantDenied, user: $otherOwner, role: 'owner'); $tenantASnapshot = seedTenantReviewEvidence($tenantA); $tenantBSnapshot = seedTenantReviewEvidence($tenantB); $tenantDeniedSnapshot = seedTenantReviewEvidence($tenantDenied); $olderPublishedReview = composeTenantReviewForTest($tenantA, $user, $tenantASnapshot); $olderPublishedReview->forceFill([ 'status' => TenantReviewStatus::Published->value, 'generated_at' => now()->subDays(3), 'published_at' => now()->subDays(3), 'published_by_user_id' => (int) $user->getKey(), ])->save(); $newerInternalReview = $olderPublishedReview->replicate(); $newerInternalReview->forceFill([ 'tenant_id' => (int) $tenantA->getKey(), 'workspace_id' => (int) $tenantA->workspace_id, 'evidence_snapshot_id' => (int) $tenantASnapshot->getKey(), 'status' => TenantReviewStatus::Ready->value, 'generated_at' => now()->subDay(), 'published_at' => null, 'published_by_user_id' => null, ])->save(); $latestPublishedReview = $olderPublishedReview->replicate(); $latestPublishedReview->forceFill([ 'tenant_id' => (int) $tenantA->getKey(), 'workspace_id' => (int) $tenantA->workspace_id, 'evidence_snapshot_id' => (int) $tenantASnapshot->getKey(), 'status' => TenantReviewStatus::Published->value, 'generated_at' => now(), 'published_at' => now(), 'published_by_user_id' => (int) $user->getKey(), ])->save(); $betaPublishedReview = composeTenantReviewForTest($tenantB, $user, $tenantBSnapshot); $betaPublishedReview->forceFill([ 'status' => TenantReviewStatus::Published->value, 'generated_at' => now()->subHours(2), 'published_at' => now()->subHours(2), 'published_by_user_id' => (int) $user->getKey(), ])->save(); $deniedPublishedReview = composeTenantReviewForTest($tenantDenied, $otherOwner, $tenantDeniedSnapshot); $deniedPublishedReview->forceFill([ 'status' => TenantReviewStatus::Published->value, 'generated_at' => now()->subHours(3), 'published_at' => now()->subHours(3), 'published_by_user_id' => (int) $otherOwner->getKey(), ])->save(); $this->actingAs($user); setAdminPanelContext(); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id); Livewire::actingAs($user) ->test(CustomerReviewWorkspace::class) ->assertCanSeeTableRecords([$tenantA->fresh(), $tenantB->fresh()]) ->assertCanNotSeeTableRecords([$tenantDenied->fresh()]) ->assertSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $latestPublishedReview->fresh()], $tenantA), false) ->assertSee('Compliance evidence mapping v1') ->assertSee('This is not a certification, legal attestation, or compliance guarantee.') ->assertSee('Endpoint hardening and compliance') ->assertSee(ComplianceEvidenceMappingV1::VERSION_KEY) ->assertSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $betaPublishedReview->fresh()], $tenantB), false) ->assertDontSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $olderPublishedReview->fresh()], $tenantA), false) ->assertDontSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $newerInternalReview->fresh()], $tenantA), false) ->assertDontSee('Publish review') ->assertDontSee('Refresh review') ->assertDontSee('Create next review') ->assertDontSee('Regenerate') ->assertDontSee('Expire snapshot') ->assertDontSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $deniedPublishedReview->fresh()], $tenantDenied), false); }); it('excludes entitled tenants without a published review from customer workspace rows', function (): void { $tenantPublished = Tenant::factory()->create(['name' => 'Published Tenant']); [$user, $tenantPublished] = createUserWithTenant(tenant: $tenantPublished, role: 'readonly'); $tenantWithoutPublished = Tenant::factory()->create([ 'workspace_id' => (int) $tenantPublished->workspace_id, 'name' => 'No Published Tenant', ]); createUserWithTenant(tenant: $tenantWithoutPublished, user: $user, role: 'readonly'); $publishedSnapshot = seedTenantReviewEvidence($tenantPublished); $noPublishedSnapshot = seedTenantReviewEvidence($tenantWithoutPublished); $publishedReview = composeTenantReviewForTest($tenantPublished, $user, $publishedSnapshot); $publishedReview->forceFill([ 'status' => TenantReviewStatus::Published->value, 'published_at' => now()->subHour(), 'published_by_user_id' => (int) $user->getKey(), ])->save(); $internalOnlyReview = composeTenantReviewForTest($tenantWithoutPublished, $user, $noPublishedSnapshot); $internalOnlyReview->forceFill([ 'status' => TenantReviewStatus::Ready->value, 'published_at' => null, 'published_by_user_id' => null, ])->save(); $this->actingAs($user); setAdminPanelContext(); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantPublished->workspace_id); Livewire::actingAs($user) ->test(CustomerReviewWorkspace::class) ->assertCanSeeTableRecords([$tenantPublished->fresh()]) ->assertCanNotSeeTableRecords([$tenantWithoutPublished->fresh()]) ->assertDontSee('No published review') ->assertDontSee('No published review available yet') ->assertDontSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $internalOnlyReview->fresh()], $tenantWithoutPublished), false) ->assertSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $publishedReview->fresh()], $tenantPublished), false); }); it('uses a page-level empty state when no entitled tenant has a released review', function (): void { $tenant = Tenant::factory()->create(['name' => 'Internal Only Tenant']); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'readonly'); $snapshot = seedTenantReviewEvidence($tenant); $internalOnlyReview = composeTenantReviewForTest($tenant, $user, $snapshot); $internalOnlyReview->forceFill([ 'status' => TenantReviewStatus::Ready->value, 'published_at' => null, 'published_by_user_id' => null, ])->save(); $this->actingAs($user); setAdminPanelContext(); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id); Livewire::actingAs($user) ->test(CustomerReviewWorkspace::class) ->assertCanNotSeeTableRecords([$tenant->fresh()]) ->assertSee('No released customer reviews match this view') ->assertSee('Publish a tenant review before it appears in the customer-safe workspace.') ->assertDontSee(TenantReviewResource::tenantScopedUrl('view', ['record' => $internalOnlyReview->fresh()], $tenant), false); }); it('summarizes accepted-risk control interpretation and evidence proof availability in customer-safe workspace rows', function (): void { $tenant = Tenant::factory()->create(['name' => 'Governed Tenant']); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'readonly'); $owner = User::factory()->create(['name' => 'Risk Owner']); $finding = Finding::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'status' => Finding::STATUS_RISK_ACCEPTED, ]); FindingException::query()->create([ 'workspace_id' => (int) $tenant->workspace_id, 'tenant_id' => (int) $tenant->getKey(), 'finding_id' => (int) $finding->getKey(), 'status' => FindingException::STATUS_ACTIVE, 'current_validity_state' => FindingException::VALIDITY_VALID, 'requested_by_user_id' => (int) $user->getKey(), 'request_reason' => 'Vendor patch window accepted by the customer.', 'owner_user_id' => (int) $owner->getKey(), 'approved_by_user_id' => (int) $owner->getKey(), 'requested_at' => now()->subDays(2), 'approved_at' => now()->subDay(), 'effective_from' => now()->subDay(), 'review_due_at' => now()->addDays(14), ]); $snapshot = seedTenantReviewEvidence($tenant, findingCount: 0, driftCount: 0); $review = composeTenantReviewForTest($tenant, $user, $snapshot); $review->forceFill([ 'status' => TenantReviewStatus::Published->value, 'published_at' => now(), 'published_by_user_id' => (int) $user->getKey(), ])->save(); $this->actingAs($user); setAdminPanelContext(); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id); Livewire::actingAs($user) ->test(CustomerReviewWorkspace::class) ->assertCanSeeTableRecords([$tenant->fresh()]) ->assertSee('Review recommended') ->assertSee('1 evidence signal(s) reference this control.') ->assertSee('1 accepted-risk finding(s) qualify this view.') ->assertSee('Review the accepted-risk owner and next review date before customer delivery.') ->assertSee('Accepted risk influences this view'); }); it('defaults the customer review workspace to the remembered tenant when tenant context is available', function (): void { $tenantA = Tenant::factory()->create(['name' => 'Alpha Tenant']); [$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'readonly'); $tenantB = Tenant::factory()->create([ 'workspace_id' => (int) $tenantA->workspace_id, 'name' => 'Beta Tenant', ]); createUserWithTenant(tenant: $tenantB, user: $user, role: 'readonly'); $snapshotA = seedTenantReviewEvidence($tenantA); $snapshotB = seedTenantReviewEvidence($tenantB); $reviewA = composeTenantReviewForTest($tenantA, $user, $snapshotA); $reviewA->forceFill([ 'status' => TenantReviewStatus::Published->value, 'published_at' => now()->subDay(), 'published_by_user_id' => (int) $user->getKey(), ])->save(); $reviewB = composeTenantReviewForTest($tenantB, $user, $snapshotB); $reviewB->forceFill([ 'status' => TenantReviewStatus::Published->value, 'published_at' => now(), 'published_by_user_id' => (int) $user->getKey(), ])->save(); $this->actingAs($user); setAdminPanelContext(); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id); session()->put(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, [ (string) $tenantA->workspace_id => (int) $tenantB->getKey(), ]); Livewire::actingAs($user) ->test(CustomerReviewWorkspace::class) ->assertSet('tableFilters.tenant_id.value', (string) $tenantB->getKey()) ->filterTable('tenant_id', (string) $tenantB->getKey()) ->assertCanSeeTableRecords([$tenantB->fresh()]) ->assertCanNotSeeTableRecords([$tenantA->fresh()]); }); it('prefilters the customer review workspace from an explicit tenant query parameter and accepts external tenant identifiers', function (): void { $tenantA = Tenant::factory()->create(['name' => 'Alpha Tenant']); [$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'readonly'); $tenantB = Tenant::factory()->create([ 'workspace_id' => (int) $tenantA->workspace_id, 'name' => 'Beta Tenant', ]); createUserWithTenant(tenant: $tenantB, user: $user, role: 'readonly'); $snapshotA = seedTenantReviewEvidence($tenantA); $snapshotB = seedTenantReviewEvidence($tenantB); $reviewA = composeTenantReviewForTest($tenantA, $user, $snapshotA); $reviewA->forceFill([ 'status' => TenantReviewStatus::Published->value, 'published_at' => now(), 'published_by_user_id' => (int) $user->getKey(), ])->save(); $reviewB = composeTenantReviewForTest($tenantB, $user, $snapshotB); $reviewB->forceFill([ 'status' => TenantReviewStatus::Published->value, 'published_at' => now()->subDay(), 'published_by_user_id' => (int) $user->getKey(), ])->save(); $this->actingAs($user); setAdminPanelContext(); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id); Livewire::withQueryParams(['tenant' => (string) $tenantA->external_id]) ->test(CustomerReviewWorkspace::class) ->assertSet('tableFilters.tenant_id.value', (string) $tenantA->getKey()) ->filterTable('tenant_id', (string) $tenantA->getKey()) ->assertCanSeeTableRecords([$tenantA->fresh()]) ->assertCanNotSeeTableRecords([$tenantB->fresh()]); });