toHaveKeys([ 'test', 'test:fast', 'test:confidence', 'test:browser', 'test:heavy', 'test:profile', 'test:junit', 'test:report', 'test:report:confidence', 'test:report:browser', 'test:report:heavy', 'test:report:profile', 'test:report:junit', 'sail:test', ]) ->and(TestLaneManifest::commandRef('fast-feedback'))->toBe('test') ->and(TestLaneManifest::commandRef('confidence'))->toBe('test:confidence') ->and(TestLaneManifest::commandRef('browser'))->toBe('test:browser') ->and(TestLaneManifest::commandRef('heavy-governance'))->toBe('test:heavy') ->and(TestLaneManifest::commandRef('profiling'))->toBe('test:profile') ->and(TestLaneManifest::commandRef('junit'))->toBe('test:junit'); }); it('keeps the host-side lane runner and report scripts checked in at repo root', function (): void { expect(file_exists(repo_path('scripts/platform-test-lane')))->toBeTrue() ->and(file_exists(repo_path('scripts/platform-test-report')))->toBeTrue() ->and(file_exists(repo_path('scripts/platform-test-artifacts')))->toBeTrue(); }); it('keeps heavy-governance baseline capture support inside the checked-in wrappers', function (): void { $laneRunner = (string) file_get_contents(repo_path('scripts/platform-test-lane')); $reportRunner = (string) file_get_contents(repo_path('scripts/platform-test-report')); expect($laneRunner)->toContain('--capture-baseline', 'copy_heavy_baseline_artifacts', 'heavy-governance-baseline.${suffix}') ->and($reportRunner)->toContain('--capture-baseline', 'copy_heavy_baseline_artifacts', 'heavy-governance-baseline.${suffix}') ->and($reportRunner)->toContain('junit)', 'test:report:junit') ->and($reportRunner)->toContain('--history-file=') ->and($reportRunner)->toContain('--history-bundle=') ->and($reportRunner)->toContain('--fetch-latest-history') ->and($reportRunner)->toContain('TENANTATLAS_GITEA_TOKEN') ->and($reportRunner)->toContain('trend-history.json'); }); it('avoids expanding an empty forwarded-argument array in the lane runner', function (): void { $laneRunner = (string) file_get_contents(repo_path('scripts/platform-test-lane')); expect($laneRunner) ->toContain('if [[ ${#remaining_args[@]} -gt 0 ]]; then') ->and($laneRunner)->toContain('./vendor/bin/sail composer run --timeout=0 "${COMPOSER_SCRIPT}" -- "${remaining_args[@]}"') ->and($laneRunner)->toContain('./vendor/bin/sail composer run --timeout=0 "${COMPOSER_SCRIPT}"') ->and($laneRunner)->toContain('--workflow-id=') ->and($laneRunner)->toContain('--trigger-class='); }); it('keeps CI workflow validation and wrong-lane drift detection in the checked-in manifest', function (): void { $validExecution = TestLaneManifest::validateWorkflowExecution('pr-fast-feedback', 'fast-feedback'); $wrongLaneExecution = TestLaneManifest::validateWorkflowExecution('pr-fast-feedback', 'confidence'); expect($validExecution['valid'])->toBeTrue() ->and($validExecution['primaryFailureClassId'])->toBeNull() ->and($wrongLaneExecution['valid'])->toBeFalse() ->and($wrongLaneExecution['workflowLaneMatched'])->toBeFalse() ->and($wrongLaneExecution['primaryFailureClassId'])->toBe('wrapper-failure'); }); it('degrades invalid CI workflow context to wrapper-failure metadata instead of crashing the lane context lookup', function (): void { $originalWorkflowId = getenv('TENANTATLAS_CI_WORKFLOW_ID'); $originalTriggerClass = getenv('TENANTATLAS_CI_TRIGGER_CLASS'); putenv('TENANTATLAS_CI_WORKFLOW_ID=missing-workflow-profile'); putenv('TENANTATLAS_CI_TRIGGER_CLASS=pull-request'); try { $context = TestLaneManifest::currentCiContext('fast-feedback'); expect($context['entryPointResolved'])->toBeFalse() ->and($context['workflowLaneMatched'])->toBeFalse() ->and($context['primaryFailureClassId'])->toBe('wrapper-failure') ->and($context['unresolvedEntryPoints'])->toContain('workflow-profile'); } finally { putenv($originalWorkflowId === false ? 'TENANTATLAS_CI_WORKFLOW_ID' : sprintf('TENANTATLAS_CI_WORKFLOW_ID=%s', $originalWorkflowId)); putenv($originalTriggerClass === false ? 'TENANTATLAS_CI_TRIGGER_CLASS' : sprintf('TENANTATLAS_CI_TRIGGER_CLASS=%s', $originalTriggerClass)); } }); it('routes the foundational lane commands through stable artisan arguments', function (): void { $fastFeedbackConfig = TestLaneManifest::laneConfigurationPath('fast-feedback'); $fastFeedbackContents = (string) file_get_contents(TestLaneManifest::absolutePath($fastFeedbackConfig)); $confidenceConfig = TestLaneManifest::laneConfigurationPath('confidence'); $confidenceContents = (string) file_get_contents(TestLaneManifest::absolutePath($confidenceConfig)); $browserConfig = TestLaneManifest::laneConfigurationPath('browser'); $browserContents = (string) file_get_contents(TestLaneManifest::absolutePath($browserConfig)); $heavyConfig = TestLaneManifest::laneConfigurationPath('heavy-governance'); $heavyContents = (string) file_get_contents(TestLaneManifest::absolutePath($heavyConfig)); expect(TestLaneManifest::buildCommand('fast-feedback'))->toContain('--parallel') ->and(TestLaneManifest::buildCommand('fast-feedback'))->toContain('--configuration='.$fastFeedbackConfig) ->and($fastFeedbackContents)->not->toContain('tests/Feature/Drift/DriftBulkAcknowledgeAllMatchingConfirmationTest.php') ->and($fastFeedbackContents)->not->toContain('tests/Feature/Findings/FindingBulkActionsTest.php') ->and($fastFeedbackContents)->not->toContain('tests/Feature/Guards/ActionSurfaceContractTest.php') ->and(TestLaneManifest::buildCommand('confidence'))->toContain('--configuration='.$confidenceConfig) ->and($confidenceContents)->toContain('tests/Feature/Baselines/BaselineCompareMatrixCompareAllActionTest.php') ->and($confidenceContents)->not->toContain('tests/Feature/Drift/DriftBulkAcknowledgeAllMatchingConfirmationTest.php') ->and($confidenceContents)->not->toContain('tests/Feature/Filament/BaselineActionAuthorizationTest.php') ->and($confidenceContents)->not->toContain('tests/Feature/Filament/BaselineProfileCaptureStartSurfaceTest.php') ->and($confidenceContents)->not->toContain('tests/Feature/Filament/BaselineProfileCompareStartSurfaceTest.php') ->and($confidenceContents)->not->toContain('tests/Feature/Findings/FindingBulkActionsTest.php') ->and($confidenceContents)->not->toContain('tests/Feature/Guards/ActionSurfaceContractTest.php') ->and(TestLaneManifest::buildCommand('browser'))->toContain('--configuration='.$browserConfig) ->and($browserContents)->toContain('tests/Browser/Spec190BaselineCompareMatrixSmokeTest.php') ->and(TestLaneManifest::buildCommand('heavy-governance'))->toContain('--configuration='.$heavyConfig) ->and($heavyContents)->toContain('tests/Feature/Drift/DriftBulkAcknowledgeAllMatchingConfirmationTest.php') ->and($heavyContents)->toContain('tests/Feature/Filament/BaselineActionAuthorizationTest.php') ->and($heavyContents)->toContain('tests/Feature/Filament/BaselineProfileCaptureStartSurfaceTest.php') ->and($heavyContents)->toContain('tests/Feature/Filament/BaselineProfileCompareStartSurfaceTest.php') ->and($heavyContents)->toContain('tests/Feature/Findings/FindingBulkActionsTest.php') ->and($heavyContents)->toContain('tests/Feature/Guards/ActionSurfaceContractTest.php') ->and(TestLaneManifest::buildCommand('junit'))->toContain('--parallel'); });