$component) { $definition = WidgetRegistry::get((string) $slug); if ($definition === null) continue; if (($component['id_base'] ?? '') !== $definition->id_base()) $errors[] = $slug . ': id_base mismatch.'; if (($component['settings'] ?? []) !== $definition->normalize((array) ($component['settings'] ?? []))) $errors[] = $slug . ': settings are not normalized.'; foreach (['default', 'hover', 'focus'] as $state) { if (!in_array($state, (array) ($component['states'] ?? []), true)) $errors[] = $slug . ': missing state ' . $state . '.'; } } foreach ((array) ($fixture['reference']['files'] ?? []) as $relative => $expected) { $path = rtrim((string) ($fixture['reference']['source_root'] ?? ''), '\\/') . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, (string) $relative); if (!is_file($path) || hash_file('sha256', $path) !== $expected) $errors[] = 'Reference drift: ' . $relative; } $require_results = in_array('--require-results', $argv, true); if ($require_results) { $result_path = $root . '/tests/visual-results/manifest.json'; if (!is_file($result_path)) { $errors[] = 'Visual result manifest is missing.'; } else { $result = json_decode((string) file_get_contents($result_path), true, 512, JSON_THROW_ON_ERROR); if (($result['schema'] ?? '') !== 'aksrt.widget-visual-results.v1') $errors[] = 'Invalid visual result schema.'; $screenshots = (array) ($result['screenshots'] ?? []); foreach ($matrix as $id => $expected) { $actual = (array) ($screenshots[$id] ?? []); $path = $root . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, (string) ($expected['path'] ?? '')); if (!$actual || !is_file($path)) $errors[] = $id . ': screenshot result is missing.'; } foreach ($components as $slug => $component) { $states = (array) ($result['components'][$slug]['states'] ?? []); foreach ((array) ($component['states'] ?? []) as $state) { if (($states[$state] ?? '') !== 'pass') $errors[] = $slug . ': state not passed: ' . $state . '.'; } } $acceptance = (array) ($fixture['acceptance'] ?? []); $metrics = (array) ($result['metrics'] ?? []); if ((float) ($metrics['dimension_delta_px_max'] ?? INF) > (float) $acceptance['dimension_delta_px_max']) $errors[] = 'Dimension delta exceeds threshold.'; if ((float) ($metrics['pixel_difference_percent_max'] ?? INF) > (float) $acceptance['pixel_difference_percent_max']) $errors[] = 'Pixel difference exceeds threshold.'; if ((int) ($result['console']['errors'] ?? PHP_INT_MAX) > (int) $acceptance['console_errors_max']) $errors[] = 'Console contains errors.'; if ((int) ($result['network']['unexpected_failures'] ?? PHP_INT_MAX) > (int) $acceptance['unexpected_network_failures_max']) $errors[] = 'Network contains unexpected failures.'; if ((int) ($result['a11y']['critical'] ?? PHP_INT_MAX) > (int) $acceptance['a11y_critical_max']) $errors[] = 'Accessibility critical findings remain.'; if ((int) ($result['a11y']['serious'] ?? PHP_INT_MAX) > (int) $acceptance['a11y_serious_max']) $errors[] = 'Accessibility serious findings remain.'; if (empty($result['reduced_motion']['passed'])) $errors[] = 'Reduced-motion behavior was not verified.'; } } if ($errors) { fwrite(STDERR, "Widget golden validation failed:\n- " . implode("\n- ", array_slice($errors, 0, 50)) . "\n"); exit(1); } echo 'Widget golden fixture passed: 37 components, 222 screenshot targets, frozen reference intact'; echo $require_results ? ", runtime results passed.\n" : ", runtime results pending.\n";