chore(repo): exclude local development files
This commit is contained in:
@@ -1,229 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require dirname(__DIR__) . '/tests/widget-system/bootstrap.php';
|
||||
|
||||
use AKSRT\WidgetSystem\FieldSchema;
|
||||
use AKSRT\WidgetSystem\WidgetRegistry;
|
||||
|
||||
$root = dirname(__DIR__);
|
||||
$baseline_path = $root . '/.specs/baselines/widget-reference.json';
|
||||
$baseline = json_decode((string) file_get_contents($baseline_path), true, 512, JSON_THROW_ON_ERROR);
|
||||
if (($baseline['schema'] ?? '') !== 'aksrt.widget-reference.v1') {
|
||||
throw new RuntimeException('Frozen widget reference baseline is invalid.');
|
||||
}
|
||||
|
||||
$reference_root = rtrim((string) ($baseline['source_root'] ?? ''), '\\/');
|
||||
$reference_hashes = [];
|
||||
foreach ((array) ($baseline['files'] ?? []) as $file) {
|
||||
$relative = (string) ($file['path'] ?? '');
|
||||
$expected = (string) ($file['sha256'] ?? '');
|
||||
$path = $reference_root . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $relative);
|
||||
if (!is_file($path) || hash_file('sha256', $path) !== $expected) {
|
||||
throw new RuntimeException('Frozen reference changed or is missing: ' . $relative);
|
||||
}
|
||||
$reference_hashes[$relative] = $expected;
|
||||
}
|
||||
|
||||
$group_sources = [
|
||||
'general' => 'inc/widgets/widget-more.php',
|
||||
'content' => 'inc/widgets/widget-posts.php',
|
||||
'knowledge_product' => 'inc/widgets/widget-produck.php',
|
||||
'slider' => 'inc/widgets/widget-slider.php',
|
||||
'user' => 'inc/widgets/widget-user.php',
|
||||
];
|
||||
$viewports = [
|
||||
['name' => 'desktop', 'width' => 1440, 'height' => 1100],
|
||||
['name' => 'tablet', 'width' => 1024, 'height' => 1000],
|
||||
['name' => 'mobile', 'width' => 390, 'height' => 844],
|
||||
];
|
||||
$modes = ['light', 'dark'];
|
||||
|
||||
$images = [
|
||||
'https://fixtures.aksrt.test/media/course-cover-01.jpg',
|
||||
'https://fixtures.aksrt.test/media/course-cover-02.jpg',
|
||||
'https://fixtures.aksrt.test/media/course-cover-03.jpg',
|
||||
];
|
||||
|
||||
function fixture_text(string $id, string $slug, int $index): string {
|
||||
$labels = [
|
||||
'question' => '购买后可以长期学习吗?',
|
||||
'answer' => '可以,已购买内容会永久保存在你的学习中心。',
|
||||
'name' => 'AKSRT 学员 ' . ($index + 1),
|
||||
'author' => 'AKSRT 学员 ' . ($index + 1),
|
||||
'role' => '知识产品体验官',
|
||||
'price' => '¥99',
|
||||
'value' => (string) (($index + 1) * 1280) . '+',
|
||||
'label' => '累计学习人数',
|
||||
'heading' => '从入门到精通的系统学习路径',
|
||||
'description' => '固定内容用于组件 DOM、响应式和视觉差异验收。',
|
||||
'content' => '结构清晰、案例完整,并持续更新配套资料。',
|
||||
'title' => 'AKSRT 固定示例 ' . ($index + 1),
|
||||
'text' => '保持好奇,持续创造。',
|
||||
];
|
||||
if (isset($labels[$id])) {
|
||||
return $labels[$id];
|
||||
}
|
||||
if (str_contains($id, 'video')) {
|
||||
return 'https://fixtures.aksrt.test/media/lesson.m3u8';
|
||||
}
|
||||
if (str_contains($id, 'url')) {
|
||||
return 'https://fixtures.aksrt.test/' . $slug . '/' . ($index + 1);
|
||||
}
|
||||
if (str_contains($id, 'ids')) {
|
||||
return str_contains($id, 'term') || str_contains($id, 'category') ? '101,102,103' : '';
|
||||
}
|
||||
return 'AKSRT ' . str_replace('_', ' ', $id) . ' ' . ($index + 1);
|
||||
}
|
||||
|
||||
function fixture_value(array $field, string $slug, int $index, array $images) {
|
||||
$type = (string) ($field['type'] ?? 'text');
|
||||
$id = (string) ($field['id'] ?? '');
|
||||
$default = $field['default'] ?? null;
|
||||
if ($id === 'title') return 'AKSRT · ' . ucfirst(str_replace('_', ' ', $slug));
|
||||
if ($id === 'subtitle') return '固定内容与交互状态视觉验收';
|
||||
if ($id === 'title_highlight') return 'AKSRT';
|
||||
if ($id === 'show_type') return 'all';
|
||||
if ($id === 'show_id_type' || $id === 'show_ids') return '';
|
||||
if ($id === 'layout_bg') {
|
||||
return [
|
||||
'light' => ['color' => '#ffffff', 'image' => '', 'position' => 'center center', 'repeat' => 'no-repeat', 'attachment' => 'scroll', 'size' => 'cover'],
|
||||
'dark' => ['color' => '#1d1e24', 'image' => '', 'position' => 'center center', 'repeat' => 'no-repeat', 'attachment' => 'scroll', 'size' => 'cover'],
|
||||
];
|
||||
}
|
||||
if ($type === 'group') {
|
||||
$rows = [];
|
||||
$count = min(3, max(1, (int) ($field['max_items'] ?? 3)));
|
||||
for ($row = 0; $row < $count; $row++) {
|
||||
$item = [];
|
||||
foreach ((array) ($field['fields'] ?? []) as $child) {
|
||||
$child_id = (string) ($child['id'] ?? '');
|
||||
if ($child_id !== '') $item[$child_id] = fixture_value($child, $slug, $row, $images);
|
||||
}
|
||||
$rows[] = $item;
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
if (in_array($type, ['fieldset', 'accordion'], true)) {
|
||||
$value = [];
|
||||
foreach ((array) ($field['fields'] ?? []) as $child) {
|
||||
$child_id = (string) ($child['id'] ?? '');
|
||||
if ($child_id !== '') $value[$child_id] = fixture_value($child, $slug, $index, $images);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
if ($type === 'link') return ['url' => 'https://fixtures.aksrt.test/' . $slug, 'text' => '查看详情', 'target' => ''];
|
||||
if ($type === 'upload') return $images[$index % count($images)];
|
||||
if ($type === 'icon') return 'fas fa-graduation-cap';
|
||||
if ($type === 'color') return '#667eea';
|
||||
if ($type === 'spacing') return ['top' => 0, 'right' => 0, 'bottom' => 20, 'left' => 0];
|
||||
if ($type === 'background') return ['color' => '#ffffff', 'image' => '', 'position' => 'center center', 'repeat' => 'no-repeat', 'attachment' => 'scroll', 'size' => 'cover'];
|
||||
if ($type === 'switcher') return $default === null ? true : (bool) $default;
|
||||
if (in_array($type, ['number', 'spinner', 'slider'], true)) return $default ?? ($field['min'] ?? 1);
|
||||
if (in_array($type, ['radio', 'button_set', 'select', 'palette'], true)) return $default ?? (array_key_first((array) ($field['options'] ?? [])) ?? '');
|
||||
if ($type === 'checkbox') return $default ?? [];
|
||||
if ($id === 'title_link') return ['url' => 'https://fixtures.aksrt.test/' . $slug, 'text' => '查看更多', 'target' => ''];
|
||||
if ($default !== null && $default !== '') return $default;
|
||||
return fixture_text($id, $slug, $index);
|
||||
}
|
||||
|
||||
$dynamic = ['posts', 'tab_posts', 'oneline_posts', 'hot_posts'];
|
||||
$expandable = ['posts_toc', 'faq'];
|
||||
$tabbed = ['tab_posts', 'feature_intro'];
|
||||
$carousel = ['partners', 'notice', 'oneline_posts', 'reviews', 'slider', 'slider_media_combo'];
|
||||
$components = [];
|
||||
$matrix = [];
|
||||
foreach (WidgetRegistry::all() as $slug => $definition) {
|
||||
$settings = [];
|
||||
foreach ($definition->fields() as $field) {
|
||||
$id = (string) ($field['id'] ?? '');
|
||||
$type = (string) ($field['type'] ?? 'text');
|
||||
if ($id === '' || in_array($type, ['content', 'subheading', 'submessage'], true)) continue;
|
||||
$settings[$id] = fixture_value($field, $slug, 0, $images);
|
||||
}
|
||||
$settings = $definition->normalize($settings);
|
||||
$states = ['default', 'hover', 'focus'];
|
||||
if (in_array($slug, $expandable, true)) $states[] = 'expanded';
|
||||
if (in_array($slug, $tabbed, true)) $states[] = 'alternate-tab';
|
||||
if (in_array($slug, $carousel, true)) $states[] = 'next-slide';
|
||||
if (in_array($slug, $dynamic, true)) $states = array_merge($states, ['loading', 'empty', 'error']);
|
||||
if ($slug === 'post_pay') $states = array_merge($states, ['guest-locked', 'member-locked', 'authorized', 'unconfigured']);
|
||||
if ($slug === 'user_card') $states = array_merge($states, ['guest', 'signed-in']);
|
||||
$source = $group_sources[$definition->group()] ?? 'inc/widgets/widget-index.php';
|
||||
$components[$slug] = [
|
||||
'id_base' => $definition->id_base(),
|
||||
'name' => $definition->name(),
|
||||
'group' => $definition->group(),
|
||||
'size' => $definition->size(),
|
||||
'reference' => ['file' => $source, 'sha256' => $reference_hashes[$source] ?? ''],
|
||||
'field_ids' => array_values(array_filter(array_map(static fn(array $field): string => (string) ($field['id'] ?? ''), $definition->fields()))),
|
||||
'settings' => $settings,
|
||||
'root_selector' => '[data-aksrt-widget="' . $slug . '"]',
|
||||
'states' => array_values(array_unique($states)),
|
||||
];
|
||||
foreach ($viewports as $viewport) {
|
||||
foreach ($modes as $mode) {
|
||||
$id = $slug . ':' . $viewport['name'] . ':' . $mode;
|
||||
$matrix[$id] = [
|
||||
'widget' => $slug,
|
||||
'viewport' => $viewport,
|
||||
'mode' => $mode,
|
||||
'path' => 'tests/visual-results/' . $slug . '/' . $viewport['name'] . '-' . $mode . '.png',
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$fixture = [
|
||||
'schema' => 'aksrt.widget-golden.v1',
|
||||
'captured_at' => (string) ($baseline['captured_at'] ?? ''),
|
||||
'reference' => [
|
||||
'source_root' => $reference_root,
|
||||
'fingerprint' => hash('sha256', implode('', $reference_hashes)),
|
||||
'files' => $reference_hashes,
|
||||
'policy' => $baseline['source_policy'] ?? [],
|
||||
],
|
||||
'acceptance' => [
|
||||
'dimension_delta_px_max' => 2,
|
||||
'pixel_difference_percent_max' => 1.5,
|
||||
'console_errors_max' => 0,
|
||||
'unexpected_network_failures_max' => 0,
|
||||
'a11y_critical_max' => 0,
|
||||
'a11y_serious_max' => 0,
|
||||
'reduced_motion_required' => true,
|
||||
],
|
||||
'dataset' => [
|
||||
'site' => ['name' => 'AKSRT 知识库', 'url' => 'https://fixtures.aksrt.test'],
|
||||
'terms' => [
|
||||
['id' => 101, 'taxonomy' => 'category', 'name' => '产品设计', 'count' => 24],
|
||||
['id' => 102, 'taxonomy' => 'category', 'name' => '前端开发', 'count' => 36],
|
||||
['id' => 103, 'taxonomy' => 'post_tag', 'name' => '系统课程', 'count' => 18],
|
||||
],
|
||||
'users' => [
|
||||
['id' => 201, 'name' => '林知夏', 'role' => '讲师', 'points' => 9680, 'followers' => 3280],
|
||||
['id' => 202, 'name' => '周屿', 'role' => '作者', 'points' => 7420, 'followers' => 2160],
|
||||
['id' => 203, 'name' => '陈墨', 'role' => '学员', 'points' => 5360, 'followers' => 980],
|
||||
],
|
||||
'posts' => [
|
||||
['id' => 301, 'title' => '从零构建知识产品体系', 'pay_type' => 'reading', 'author' => 201, 'category' => 101],
|
||||
['id' => 302, 'title' => '现代 WordPress 主题工程实践', 'pay_type' => 'video', 'author' => 202, 'category' => 102],
|
||||
['id' => 303, 'title' => '高质量课程资料包', 'pay_type' => 'download', 'author' => 201, 'category' => 102],
|
||||
['id' => 304, 'title' => '视觉案例图库', 'pay_type' => 'gallery', 'author' => 202, 'category' => 101],
|
||||
['id' => 305, 'title' => '会员专属进阶课', 'pay_type' => 'vip', 'author' => 201, 'category' => 101],
|
||||
['id' => 306, 'title' => '公开学习指南', 'pay_type' => 'no', 'author' => 203, 'category' => 102],
|
||||
],
|
||||
'comments' => [
|
||||
['id' => 401, 'user' => 203, 'post' => 301, 'content' => '课程结构清晰,案例非常实用。'],
|
||||
['id' => 402, 'user' => 202, 'post' => 302, 'content' => '对主题工程化讲解得很完整。'],
|
||||
],
|
||||
'payment_states' => ['guest-locked', 'member-locked', 'free', 'purchased', 'vip-authorized', 'unconfigured'],
|
||||
'media' => ['images' => $images, 'video' => 'https://fixtures.aksrt.test/media/lesson.m3u8'],
|
||||
],
|
||||
'components' => $components,
|
||||
'screenshot_matrix' => $matrix,
|
||||
];
|
||||
|
||||
$output = $root . '/tests/fixtures/widget-golden-v1.json';
|
||||
file_put_contents($output, json_encode($fixture, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n");
|
||||
echo 'Generated widget golden fixture: ' . count($components) . ' components, ' . count($matrix) . " screenshots.\n";
|
||||
Reference in New Issue
Block a user