Added UiBloatRegressionGuardTest to enforce known UI bloat and customer/auditor safety regression patterns across configured runtime UI source paths as defined in Spec 375. Registered the test in Pest.php and added to TestLaneManifest. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #446
180 lines
7.8 KiB
PHP
180 lines
7.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use Tests\Support\TestLaneManifest;
|
|
use Tests\Support\UiBloat\UiBloatScanner;
|
|
|
|
function spec375AllowlistEntry(array $overrides = []): array
|
|
{
|
|
return array_merge([
|
|
'rule_id' => 'UIBLOAT_CUSTOMER_RAW_ID',
|
|
'file' => 'apps/platform/resources/views/filament/pages/reviews/customer-review-workspace.blade.php',
|
|
'pattern' => 'operation id',
|
|
'reason' => 'Appears only inside collapsed technical details.',
|
|
'surface_type' => 'customer-auditor',
|
|
'audience' => 'operator-support',
|
|
'review_marker' => 'manual-review-required',
|
|
'expires_or_review_after' => '2026-09-01',
|
|
'owner_spec' => 'specs/375-ui-bloat-regression-guard',
|
|
], $overrides);
|
|
}
|
|
|
|
it('keeps the ui bloat guard in surface-guard heavy-governance ownership', function (): void {
|
|
$family = TestLaneManifest::family('ui-bloat-regression-guard');
|
|
|
|
expect($family['classificationId'])->toBe('surface-guard')
|
|
->and($family['targetLaneId'])->toBe('heavy-governance')
|
|
->and($family['hotspotFiles'])->toContain('tests/Feature/Guards/UiBloatRegressionGuardTest.php');
|
|
});
|
|
|
|
it('supports report warn and fail strictness semantics', function (): void {
|
|
$file = 'apps/platform/resources/views/filament/pages/reviews/customer-review-workspace.blade.php';
|
|
$source = '<section>Customer review output <p>Operation context</p></section>';
|
|
|
|
$report = UiBloatScanner::scanSource($file, $source, UiBloatScanner::STRICTNESS_REPORT);
|
|
$warn = UiBloatScanner::scanSource($file, $source, UiBloatScanner::STRICTNESS_WARN);
|
|
$fail = UiBloatScanner::scanSource(
|
|
'apps/platform/app/Filament/Pages/Operations.php',
|
|
'<x-filament-panels::page><p>0 alerts</p></x-filament-panels::page>',
|
|
UiBloatScanner::STRICTNESS_FAIL,
|
|
);
|
|
|
|
expect($report['blocking_failures'])->toBeEmpty()
|
|
->and($warn['blocking_failures'])->not->toBeEmpty()
|
|
->and($fail['blocking_failures'])->not->toBeEmpty();
|
|
});
|
|
|
|
it('hard-fails customer raw id labels unless allowlisted', function (): void {
|
|
$file = 'apps/platform/resources/views/filament/pages/reviews/customer-review-workspace.blade.php';
|
|
$source = '<section>Customer review output <p>Operation ID</p></section>';
|
|
|
|
$result = UiBloatScanner::scanSource($file, $source);
|
|
$allowlisted = UiBloatScanner::scanSource($file, $source, UiBloatScanner::STRICTNESS_WARN, [
|
|
spec375AllowlistEntry(),
|
|
]);
|
|
|
|
expect($result['blocking_failures'])->toHaveCount(1)
|
|
->and($result['blocking_failures'][0]['rule_id'])->toBe('UIBLOAT_CUSTOMER_RAW_ID')
|
|
->and($allowlisted['blocking_failures'])->toBeEmpty()
|
|
->and($allowlisted['findings'][0]['result'])->toBe('allowlisted');
|
|
});
|
|
|
|
it('hard-fails customer internal provider or debug terms unless allowlisted', function (): void {
|
|
$file = 'apps/platform/resources/views/filament/pages/reviews/customer-review-workspace.blade.php';
|
|
$source = '<section>Customer review output <p>Raw Graph payload</p></section>';
|
|
|
|
$result = UiBloatScanner::scanSource($file, $source);
|
|
$allowlisted = UiBloatScanner::scanSource($file, $source, UiBloatScanner::STRICTNESS_WARN, [
|
|
spec375AllowlistEntry([
|
|
'rule_id' => 'UIBLOAT_CUSTOMER_INTERNAL_TERM',
|
|
'pattern' => 'raw graph payload',
|
|
'reason' => 'Fixture proves scoped exception behavior.',
|
|
]),
|
|
]);
|
|
|
|
expect($result['blocking_failures'])->toHaveCount(1)
|
|
->and($result['blocking_failures'][0]['rule_id'])->toBe('UIBLOAT_CUSTOMER_INTERNAL_TERM')
|
|
->and($allowlisted['blocking_failures'])->toBeEmpty();
|
|
});
|
|
|
|
it('keeps zero metrics and repeated status as non-blocking review findings in warn mode', function (): void {
|
|
$source = str_repeat('Status ready lifecycle completed. ', 18).'<p>0 findings</p>';
|
|
$result = UiBloatScanner::scanSource('apps/platform/app/Filament/Pages/EnvironmentDashboard.php', $source);
|
|
|
|
expect($result['blocking_failures'])->toBeEmpty()
|
|
->and(array_keys($result['summary_by_rule']))->toContain('UIBLOAT_ZERO_METRIC_CARD', 'UIBLOAT_REPEATED_STATUS')
|
|
->and($result['summary_by_result'])->toHaveKey('warning')
|
|
->and($result['summary_by_result'])->toHaveKey('manual-review-required');
|
|
});
|
|
|
|
it('reports decision hierarchy action overload evidence diagnostic mixing and metadata findings as manual review', function (): void {
|
|
$pageSource = <<<'PHP'
|
|
<?php
|
|
final class ExamplePage
|
|
{
|
|
protected function getHeaderActions(): array
|
|
{
|
|
return [
|
|
Action::make('one'),
|
|
Action::make('two'),
|
|
Action::make('three'),
|
|
Action::make('four'),
|
|
Action::make('five'),
|
|
];
|
|
}
|
|
}
|
|
// Evidence diagnostics
|
|
PHP;
|
|
|
|
$pageResult = UiBloatScanner::scanSource('apps/platform/app/Filament/Pages/ExamplePage.php', $pageSource);
|
|
$metadataResult = UiBloatScanner::scanSource(
|
|
'apps/platform/app/Filament/Resources/ExampleResource.php',
|
|
'<?php // Normalization lineage',
|
|
);
|
|
|
|
$ruleIds = array_unique(array_merge(
|
|
array_keys($pageResult['summary_by_rule']),
|
|
array_keys($metadataResult['summary_by_rule']),
|
|
));
|
|
|
|
expect($ruleIds)->toContain(
|
|
'UIBLOAT_MISSING_PRIMARY_QUESTION',
|
|
'UIBLOAT_HEADER_ACTION_OVERLOAD',
|
|
'UIBLOAT_EVIDENCE_DIAGNOSTICS_MIXED',
|
|
'UIBLOAT_TECH_METADATA_MAIN',
|
|
)
|
|
->and($pageResult['blocking_failures'])->toBeEmpty()
|
|
->and($metadataResult['blocking_failures'])->toBeEmpty();
|
|
});
|
|
|
|
it('reports diagnostic guidance and ambiguous entrypoint drift as manual review', function (): void {
|
|
$source = <<<'BLADE'
|
|
<x-filament-panels::page>
|
|
<h1>Diagnostics hub</h1>
|
|
<p>Raw payload provider context debug trace operation id diagnostic details.</p>
|
|
</x-filament-panels::page>
|
|
BLADE;
|
|
|
|
$result = UiBloatScanner::scanSource('apps/platform/app/Filament/Pages/EnvironmentDiagnostics.php', $source);
|
|
|
|
expect(array_keys($result['summary_by_rule']))->toContain(
|
|
'UIBLOAT_DIAGNOSTIC_GUIDANCE_MISSING',
|
|
'UIBLOAT_DIAGNOSTIC_ENTRYPOINT_AMBIGUOUS',
|
|
)
|
|
->and($result['blocking_failures'])->toBeEmpty();
|
|
});
|
|
|
|
it('validates allowlist entry shape and rejects blanket entries', function (): void {
|
|
$errors = UiBloatScanner::validateAllowlist([
|
|
[
|
|
'rule_id' => 'UIBLOAT_CUSTOMER_RAW_ID',
|
|
'file' => 'apps/platform/app/Filament',
|
|
],
|
|
]);
|
|
|
|
expect($errors)->not->toBeEmpty()
|
|
->and(implode("\n", $errors))->toContain('reason')
|
|
->and(implode("\n", $errors))->toContain('forbidden blanket file pattern');
|
|
});
|
|
|
|
it('excludes non-runtime paths from ui findings by default', function (): void {
|
|
expect(UiBloatScanner::isRuntimeUiPath('apps/platform/routes/web.php'))->toBeFalse()
|
|
->and(UiBloatScanner::isRuntimeUiPath('apps/platform/app/Models/User.php'))->toBeFalse()
|
|
->and(UiBloatScanner::isRuntimeUiPath('specs/375-ui-bloat-regression-guard/spec.md'))->toBeFalse()
|
|
->and(UiBloatScanner::isRuntimeUiPath('apps/platform/tests/Feature/Guards/UiBloatRegressionGuardTest.php'))->toBeFalse()
|
|
->and(UiBloatScanner::isRuntimeUiPath('apps/platform/app/Filament/Pages/ExamplePage.php'))->toBeTrue();
|
|
});
|
|
|
|
it('scans the configured runtime ui paths without unallowlisted customer safety blockers', function (): void {
|
|
$result = UiBloatScanner::scanConfiguredPaths(repo_path(), UiBloatScanner::STRICTNESS_WARN);
|
|
|
|
expect($result['files_scanned'])->toBeGreaterThan(0)
|
|
->and($result['config_errors'])->toBeEmpty()
|
|
->and($result['blocking_failures'])->toBeEmpty(
|
|
"Unexpected customer/auditor blocking UI bloat findings:\n".UiBloatScanner::formatFindings($result['blocking_failures']),
|
|
)
|
|
->and($result['absent_candidate_paths']['apps/platform/resources/views/components'])->toBe('not available')
|
|
->and($result['absent_candidate_paths']['apps/platform/app/View'])->toBe('not available');
|
|
});
|