TenantAtlas/tests/Feature/Filament/BaselineCompareEvidenceGapTableTest.php
ahmido 7d4d607475 feat: add baseline gap details surfaces (#192)
## Summary
- add baseline compare evidence gap detail modeling and a dedicated Livewire table surface
- extend baseline compare landing and operation run detail surfaces to expose evidence gap details and stats
- add spec artifacts for feature 162 and expand feature coverage with focused Filament and baseline tests

## Notes
- branch: `162-baseline-gap-details`
- commit: `a92dd812`
- working tree was clean after push

## Validation
- tests were not run in this step

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #192
2026-03-24 19:05:23 +00:00

115 lines
4.1 KiB
PHP

<?php
declare(strict_types=1);
use App\Livewire\BaselineCompareEvidenceGapTable;
use App\Support\Badges\TagBadgeCatalog;
use App\Support\Badges\TagBadgeDomain;
use App\Support\Baselines\BaselineCompareEvidenceGapDetails;
use Filament\Tables\Table;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Features\SupportTesting\Testable;
use Livewire\Livewire;
uses(RefreshDatabase::class);
function baselineCompareEvidenceGapTable(Testable $component): Table
{
return $component->instance()->getTable();
}
/**
* @return list<array<string, mixed>>
*/
function baselineCompareEvidenceGapBuckets(): array
{
return BaselineCompareEvidenceGapDetails::fromContext([
'baseline_compare' => [
'evidence_gaps' => [
'count' => 5,
'by_reason' => [
'ambiguous_match' => 3,
'policy_not_found' => 2,
],
'subjects' => [
'ambiguous_match' => [
'deviceConfiguration|WiFi-Corp-Profile',
'deviceConfiguration|VPN-Always-On',
'deviceCompliancePolicy|Windows-Encryption-Required',
],
'policy_not_found' => [
'deviceConfiguration|Deleted-Policy-ABC',
'deviceCompliancePolicy|Retired-Compliance-Policy',
],
],
],
],
])['buckets'];
}
it('uses a Filament table for evidence-gap rows with searchable visible columns', function (): void {
$component = Livewire::test(BaselineCompareEvidenceGapTable::class, [
'buckets' => baselineCompareEvidenceGapBuckets(),
'context' => 'canonical-run',
]);
$table = baselineCompareEvidenceGapTable($component);
expect($table->isSearchable())->toBeTrue();
expect($table->getDefaultSortColumn())->toBe('reason_label');
expect($table->getColumn('reason_label')?->isSearchable())->toBeTrue();
expect($table->getColumn('policy_type')?->isSearchable())->toBeTrue();
expect($table->getColumn('subject_key')?->isSearchable())->toBeTrue();
$component
->assertSee('WiFi-Corp-Profile')
->assertSee('Deleted-Policy-ABC')
->assertSee('Reason')
->assertSee('Policy type')
->assertSee('Subject key')
->assertSee(TagBadgeCatalog::spec(TagBadgeDomain::PolicyType, 'deviceConfiguration')->label)
->assertSee(TagBadgeCatalog::spec(TagBadgeDomain::PolicyType, 'deviceCompliancePolicy')->label);
});
it('filters evidence-gap rows by table search and select filters', function (): void {
Livewire::test(BaselineCompareEvidenceGapTable::class, [
'buckets' => baselineCompareEvidenceGapBuckets(),
'context' => 'tenant-landing',
])
->searchTable('Deleted-Policy-ABC')
->assertSee('Deleted-Policy-ABC')
->assertDontSee('WiFi-Corp-Profile');
Livewire::test(BaselineCompareEvidenceGapTable::class, [
'buckets' => baselineCompareEvidenceGapBuckets(),
'context' => 'tenant-landing-filters',
])
->filterTable('reason_code', 'policy_not_found')
->assertSee('Retired-Compliance-Policy')
->assertDontSee('VPN-Always-On')
->filterTable('policy_type', 'deviceCompliancePolicy')
->assertSee('Retired-Compliance-Policy')
->assertDontSee('Deleted-Policy-ABC');
});
it('shows an explicit empty state when only missing-detail buckets exist', function (): void {
$buckets = BaselineCompareEvidenceGapDetails::fromContext([
'baseline_compare' => [
'evidence_gaps' => [
'count' => 2,
'by_reason' => [
'policy_not_found' => 2,
],
'subjects' => [],
],
],
])['buckets'];
Livewire::test(BaselineCompareEvidenceGapTable::class, [
'buckets' => $buckets,
'context' => 'legacy-run',
])
->assertSee('No recorded gap rows match this view')
->assertSee('Adjust the current search or filters to review other affected subjects.');
});