feat(S6-P21): 组件族参数化(13族/44成员/导航族15文件同源/79→48概念组件)
【本次核心 · S6-P21】 - 族层数据:families.json + 44 份契约注入 family/familyRole/familyParams; data.json / data.js / site/details 同步。13 族 / 44 成员 / 35 独立 → 概念组件 79→48。 - 79 个 slug 全保留、集合逐一不变(铁律 5 对外承诺未破);frameworks 仍 395 文件、薄壳仍 79。 - 归族判据为契约中可核对字段(semanticTypeCandidates 重叠 / anatomy 为同一骨架子集 / 变体维度同构 / doNotInvent 显式从属声明),每族 mergeBasis 写明依据,不按名字猜。 - 实现层合并(导航族端到端切片):tools/gen-family-impl.mjs 从 5 端模板生成 TopMenu / SideMenu / MixedNavigation 共 15 文件,参数 direction=top|side|mixed; 三份 CSS md5 完全相同 = 一份样式表服务三个组件。 - 新增 tools/gen-families.mjs、tools/gen-family-impl.mjs、tools/verify-families.mjs、 tools/lib/family-model.mjs、tools/lib/family-impl/nav-menu/*.tpl。 【同时清掉此前已完成但未提交的批次】 生成物(data.json / data.js / site/sources / site/components 薄壳 / sitemap.xml / tests 报告) 跨阶段交织,无法拆成互相自洽的多个提交,故按既有批量风格合并提交: - Package:三端可 import(S5-P18)+ 发布到私有 npm 源 - Docs site:导航语言改下拉(S5-P19)、详情页代码块默认展开、中英切换完整性 - Security:生产部署链审计修复(2026-09-19)+ 线上部署 - Theme modes 日间/夜间/自动;S1-P4 data.js 瘦身;S2-P5 暗色;S2-P6 跨端一致性; S2-P7 行为断言;S2-P9 FAQ;S3-P8 RTL;S3-P9 契约缺口解释层;S4-P12 发布流程 - 补入 tools/pack-deploy.mjs、run-site-smoke.mjs、verify-*.mjs,.dockerignore、 安全审计修复与待决策项.md 【验收】 - node tools/verify-families.mjs → OK: 族层端到端一致(13 族 / 44 成员 / 79 组件不变 / 395 文件不变) - node tools/verify-cross-platform.mjs → 79/79 identical(HEAD 基线 high 44) - node tools/run-regression.mjs → 100%(79/79 页,1017/1017 断言,N/A 34),连跑 8 次一致,0 超时 - 逐页实测:topmenu / sidemenu / mixednavigation 各 13/13,帧内 direction 参数正确,0 JS 错误 - 零运行时依赖 OK;build-site.ps1 ASCII-only OK 【未纳入】site/components/<slug>/ 平台薄壳 316 个 —— 历史从未跟踪且属构建产物,保持现状。
This commit is contained in:
+65
-94
@@ -1,92 +1,88 @@
|
||||
# 测试说明
|
||||
|
||||
Aurora Admin 组件库的测试设计:**零依赖、可视化、可机读**。每个组件都有一份独立的测试页 `tests/<slug>.html`,加上 `tests/index.html` 总览入口。
|
||||
Aurora Admin 的测试设计:**零运行时依赖、可视化、可机读**。设计系统包含 **79 个全量组件契约**,每个组件对应 4 个运行端(H5 / React / Vue 2 / Vue 3)以及 CSS 资产;`tests/<slug>.html` 是 H5 回归测试页。
|
||||
|
||||
## headless 回归(v1.2.0 起,v1.3.0 修正口径)
|
||||
## 环境与安装
|
||||
|
||||
需要 **Node 20+**。`package.json` 的 `dependencies` 必须为空;Playwright 属于 CI/本地验证用 `devDependency`。
|
||||
|
||||
```bash
|
||||
node site/dev-server.js # 先起站
|
||||
node tools/run-regression.mjs # 需 npm i playwright;输出 tests/report.json + report-junit.xml
|
||||
npm ci
|
||||
```
|
||||
|
||||
无 playwright 的机器用浏览器跑法(零依赖):打开 `tests/_collect.html`,它把 79 个测试页并发装入同源 iframe,汇总后写入 `window.__aaCollectResult`(同 `report.json` 结构),从控制台取出落盘即可。
|
||||
## Headless 回归
|
||||
|
||||
- `tests/report.json` 是首页「测试通过率」的数据源;无报告时首页静默隐藏该数字。
|
||||
- 当前基线:961 条断言,通过率 **100%**(0 失败 / 36 条 N/A)、79 页全通过。
|
||||
- **通过率 = pass / (pass + fail)**,N/A(静态组件无交互面、单实例组件无多变体等)不计入分母。
|
||||
- N/A 是**合理豁免**而非缺陷掩盖:`dashboardcard`/`chartpanel`/`emptypro` 这类纯展示组件确实没有交互面;`watermark`/`transfer`/`listpicker` 确实只有一份实例。判定依据已逐条人工核实。
|
||||
```bash
|
||||
node site/dev-server.js # 先起站,监听 127.0.0.1:3311
|
||||
node tools/verify-dev-server.mjs # 本地服务的畸形请求/穿越防护(含 3 条反例断言)
|
||||
node tools/verify-emits-parse.mjs # defineEmits 字面量解析:运行时与构建期双实现等价
|
||||
node tools/verify-i18n.mjs
|
||||
node tools/verify-site-routing.mjs
|
||||
node tools/verify-cross-platform.mjs
|
||||
node tools/run-regression.mjs # 输出 tests/report.json + report-junit.xml
|
||||
npm run smoke:site
|
||||
```
|
||||
|
||||
### 通过率的边界(务必明确)
|
||||
`tools/verify-dev-server.mjs` 会用 `AA_PORT`(默认 13311)另起一份服务,因此不会与手工起的 3311 实例抢端口;`tools/run-regression.mjs` 支持 `REG_BASE` 指向别的端口。
|
||||
|
||||
这 9 项自动化断言覆盖的是**结构性规则**,通过率 100% **不等同于 WCAG 2.1 AA 合规**。未覆盖的部分需要人工或辅助技术实测:
|
||||
CI 使用 Node 20、严格 `npm ci` 和 `npx --no-install`,并缓存 Playwright 浏览器。站点服务已启动后,`smoke:site` 会验证文档站语言、路由、详情、目录、主题面板、框架保持和刷新恢复。
|
||||
|
||||
无 Playwright 的机器可以打开 `tests/_collect.html`,它把 79 个测试页装入同源 iframe,汇总结果到 `window.__aaCollectResult`;这条浏览器路径适合人工取证,不替代 CI headless 回归。
|
||||
|
||||
## 当前基线
|
||||
|
||||
所有数字以当前 `tests/report.json` 为准。当前报告(v1.4.1,2026-09-19 实测)为:79/79 页面通过,**1017 通过、0 失败、34 N/A,共 1051 条断言**;通过率 100%。N/A 不计入通过率分母。
|
||||
|
||||
> 口径说明:此前记录的 1009 / 35 / 1044 是更早工作树状态下的数字。当前数字来自本仓库工作树连续 10 次回归(9 次连跑 + 1 次独立复跑)的一致结果。
|
||||
|
||||
`tests/report.json` 是文档站首页测试摘要的数据源。不要手工修改报告数字,必须修复实际问题后重跑生成。
|
||||
|
||||
## A11y 基线与边界
|
||||
|
||||
自动化断言将 A11y 作为结构基线,覆盖键盘可达、焦点环、ARIA、文本/图形对比度和 token 使用等规则。通过率不等同于完整 WCAG 2.1 AA 合规声明。以下内容仍需人工或辅助技术实测:
|
||||
|
||||
- 屏幕阅读器朗读顺序与播报质量(NVDA / VoiceOver)
|
||||
- 焦点顺序是否合乎视觉逻辑、焦点陷阱(弹窗内 Tab 循环)
|
||||
- 动态内容变更的播报时机(`aria-live` 的实际体验)
|
||||
- 表单错误提示与字段的关联(`aria-describedby` 指向是否准确)
|
||||
- 缩放至 200% 时的布局可用性(WCAG 1.4.4)
|
||||
- 焦点顺序、焦点陷阱以及弹窗内 Tab 循环
|
||||
- 动态内容变更与 `aria-live` 播报时机
|
||||
- 表单错误提示和 `aria-describedby` 关联
|
||||
- 200% 缩放时的布局可用性
|
||||
|
||||
### 断言为什么跑在 iframe 里
|
||||
## RTL 现状与限制
|
||||
|
||||
79 个 H5 演示页的 DOM **全部由内联脚本渲染**(body 只有 `<div id="app"></div>` + `<script>render()</script>`)。v1.2.0 曾尝试把演示页 body 抽成静态快照,但剥离 `<script>` 后 DOM 为空,且测试页未引用 `frameworks/<组件>.css`——断言在空 DOM 上必然大面积失败,当时的 75.1% 是结构性误报。
|
||||
RTL 已纳入样式迁移与验证范围,部分组件使用 CSS 逻辑属性(如 `margin-inline-*`、`padding-inline-*`、`border-inline-*`)。可在宿主页面或场景页设置 `dir="rtl"` 做定向验收。当前仓库没有把 RTL 宣称为 79 个组件全量完成的视觉验收;图标方向、复杂组合布局、溢出和交互顺序仍需逐组件人工复核。
|
||||
|
||||
因此测试页 `<iframe id="snapshot-frame" src="../frameworks/<组件>.html">` 直载真实演示页:CSS 与脚本真实执行,`_runtime.js` 跨帧读取 `contentDocument` 执行断言(同源可直读),用例节点在帧内自动标注 `data-assert` 并描边可视化,结果 `postMessage` 给父页与收集器。
|
||||
## 跨端结构验证
|
||||
|
||||
用例标注规则:优先 `.row / .demo-block / .demo-row` 的子元素;否则从被测范围向下寻找「首个含 ≥2 个有效子元素的容器」(最多 6 层)。页头文档文字(h1 / .sub)不计为用例。
|
||||
```bash
|
||||
node tools/verify-cross-platform.mjs
|
||||
```
|
||||
|
||||
- 注意:重建 data.js 后浏览器需 Ctrl+F5;重建测试页后无需额外处理(标注在运行期完成)。
|
||||
脚本从 `site/data.json.meta.version` 记录版本,检查 79 个组件的 H5 / React / Vue 2 / Vue 3 结构和 class 集合,并输出 `tests/cross-platform-report.json`。当前报告有 77 个历史差异;差异本身是信息项,不会导致命令失败。总数不是 79 或读取文件失败会阻断命令。
|
||||
|
||||
## 测试矩阵(每个组件都跑这 8 项)
|
||||
## 断言为什么跑在 iframe 里
|
||||
|
||||
| # | 维度 | 说明 |
|
||||
|---|---|---|
|
||||
| 1 | 默认态渲染 | 核心节点齐全(容器 + 标签 + 图标位等) |
|
||||
| 2 | 尺寸/类型变体 | 大/中/小;主/次/文字/链接/危险等(≥2 用例) |
|
||||
| 3 | 状态覆盖 | DOM 出现状态类,**或**样式表定义了状态选择器(`:hover`/`:focus`/`.is-disabled` 等——交互态本就不常驻 DOM) |
|
||||
| 4 | 可见用例 | ≥1 个用例在默认态可见(默认隐藏、交互后可见者记 skip) |
|
||||
| 5 | 键盘可达 | 可聚焦元素具备 tabindex 或原生 button/a;静态组件记 N/A |
|
||||
| 6 | 焦点环可视 | `:focus-visible` 描边规则存在(基座 `colors_and_type.css` 已统一提供) |
|
||||
| 7 | ARIA 属性 | 交互节点具备 role / aria-*;静态组件记 N/A |
|
||||
| 8 | 对比度 | 文本 ≥ 4.5:1(大字号 ≥ 3:1,WCAG 1.4.3);图标/箭头等图形 ≥ 3:1(WCAG 1.4.11,非阻塞提示);装饰性元素不约束 |
|
||||
| 9 | token 一致性 | 用例区内联 style 不出现硬编码 hex(数据驱动的颜色如色板、图表系列豁免) |
|
||||
79 个 H5 演示页的 DOM 由内联脚本渲染,测试页通过 iframe 直载真实演示页,CSS 与脚本真实执行,`_runtime.js` 跨帧读取 `contentDocument` 执行断言。用例节点在帧内自动标注 `data-assert` 和 `data-status`,结果通过 `postMessage` 汇总。
|
||||
|
||||
## 断言协议
|
||||
|
||||
每个测试用例在 DOM 上加两个属性(测试页由 `_runtime.js` 运行期标注,演示页源文件不必手写):
|
||||
## 断言协议与矩阵
|
||||
|
||||
```html
|
||||
<button class="btn btn-primary" data-assert="variant-1" data-status="pass">主按钮</button>
|
||||
<button class="btn btn-primary" data-assert="variant-2" data-status="skip" disabled>禁用态</button>
|
||||
```
|
||||
|
||||
- `data-assert`:唯一断言 ID(`variant-<n>`,运行期自动标注)
|
||||
- `data-status`:当前结果(`pass` / `fail` / `skip`)
|
||||
每个测试页覆盖以下结构规则:
|
||||
|
||||
「运行断言」会执行两类检查并把 `data-status` 写回帧内节点:① 用例可见性(默认态可见记 pass,交互后才出现的记 skip);② 通用测试矩阵 9 项。失败项写 `localStorage[aa-test-log]`,可导出。
|
||||
|
||||
## 如何跑测试
|
||||
|
||||
### 方式一:浏览器手动
|
||||
|
||||
1. 打开 `tests/index.html`
|
||||
2. 点击任一组件 → 进入该组件的测试页
|
||||
3. 观察渲染快照与断言列表
|
||||
4. 点击「运行断言」得到 PASS/FAIL
|
||||
5. 顶部「导出日志」按钮下载 JSON
|
||||
|
||||
### 方式二:自动化(Playwright)
|
||||
|
||||
现成 runner 见上节 `tools/run-regression.mjs`。要点是断言在 iframe 演示页加载后自动执行,需等汇总区出现结果再读取:
|
||||
|
||||
```javascript
|
||||
const page = await ctx.newPage();
|
||||
await page.goto('http://127.0.0.1:3311/tests/button.html');
|
||||
await page.waitForFunction(() => document.getElementById('sum-total')?.textContent !== '总数 0');
|
||||
const r = await page.evaluate(() => ({
|
||||
total: Number(document.getElementById('sum-total').textContent.replace(/\D/g, '')),
|
||||
fail: [...document.querySelectorAll('#result-list .t-row .t-pill.fail')].length
|
||||
}));
|
||||
```
|
||||
| # | 维度 | 说明 |
|
||||
|---|---|---|
|
||||
| 1 | 默认态渲染 | 核心节点齐全 |
|
||||
| 2 | 尺寸/类型变体 | 代表性尺寸、类型和状态 |
|
||||
| 3 | 状态覆盖 | 状态类或状态选择器存在 |
|
||||
| 4 | 可见用例 | 至少一个默认态可见用例 |
|
||||
| 5 | 键盘可达 | 原生可聚焦元素或 tabindex |
|
||||
| 6 | 焦点环可视 | 存在 `:focus-visible` 描边规则 |
|
||||
| 7 | ARIA 属性 | 交互节点具备 role / aria-* |
|
||||
| 8 | 对比度 | 文本及图形对比度基线 |
|
||||
| 9 | token 一致性 | 用例区不硬编码颜色 |
|
||||
|
||||
## 重新生成测试目录
|
||||
|
||||
@@ -94,39 +90,14 @@ const r = await page.evaluate(() => ({
|
||||
powershell -File run-tests.ps1
|
||||
```
|
||||
|
||||
按 `components/index.json` 的 79 项生成 `tests/<slug>.html`(iframe 版)与 `tests/index.html`,并报告缺失的演示页。模板在 `tests/_template.html`(单页)与 `tests/_index_template.html`(总览页)——改测试页结构请改模板后重跑,不要手改生成的 `<slug>.html`。
|
||||
按 `.design_library/aurora-admin/components/index.json` 的 79 项生成测试页。修改测试结构时改 `tests/_template.html` 或 `tests/_index_template.html` 后重跑,不要手改生成的组件页。
|
||||
|
||||
脚本保持 ASCII-only(PS5.1 按 ANSI 读取无 BOM 文件,非 ASCII 字面量会被损坏);中文文案一律放在 UTF-8 模板里。输出用 `WriteAllText` 无 BOM 写出。
|
||||
## 文档站冒烟
|
||||
|
||||
## 日志格式
|
||||
|
||||
`localStorage[aa-test-log]` JSON 结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"ts": 1757232000000,
|
||||
"slug": "button",
|
||||
"page": "tests/button.html",
|
||||
"assertions": [
|
||||
{ "id": "btn-primary-default", "status": "pass", "durationMs": 12 },
|
||||
{ "id": "btn-disabled", "status": "pass", "durationMs": 8 }
|
||||
],
|
||||
"errors": []
|
||||
}
|
||||
```bash
|
||||
node site/dev-server.js
|
||||
npm run verify:i18n
|
||||
npm run smoke:site
|
||||
```
|
||||
|
||||
控制台输入 `aaLogger.export('test')` 导出当前所有日志。
|
||||
|
||||
## 与文档站的关系
|
||||
|
||||
- 文档站 `site/app.js` 详情页有「测试页」按钮直达 `tests/<slug>.html`
|
||||
- 测试页头部有「← 返回文档站」按钮回 `site/index.html`
|
||||
- 两者共用 `colors_and_type.css`,主题色随主题切换实时同步
|
||||
|
||||
## 不在本轮范围
|
||||
|
||||
- React 单元测试(Jest / Vitest)
|
||||
- 视觉回归(像素对比)
|
||||
- E2E 流程测试(点击 → 跳转)
|
||||
|
||||
这些会在 v1.2.0 之后考虑。
|
||||
冒烟覆盖默认中文、英语切换、`html[lang]`、`document.title`、导航/详情页/目录、主题面板、`aa-lang` 持久化、框架保持、路由切换、刷新恢复和切回中文。
|
||||
|
||||
Reference in New Issue
Block a user