本文是 matery 主题自动化测试体系的完整教程,与其余 4 篇功能测试文章(内容 tag / 交互视觉 / 布局页面 / Markdown 语法)配套——那 4 篇是"测试靶场",本文是"测试引擎"。权威依据:
tools/tests/release-test.sh(L1-L13)、tools/tests/run-tests.sh、docs/superpowers/specs/2026-08-06-layout-test-cases.md。
1. 测试金字塔总览
┌──────────────┐
│ L2 生产 URL │ 发版后:20 页面 HTTP 200 + 功能标记(curl)
│ L9/L10 SW │ 发版前:Vercel 测试域 SW 冒烟(playwright)
├──────────────┤
│ L11 Playwright 集成 │ 真实浏览器:特效/词云/懒加载/阅读模式等 14 项
├──────────────┤
│ L13 单测门禁 │ node 直跑:13 个 .test.js + 3 个 shell 单测
├──────────────┤
│ L1 构建验证 │ hexo g Success + 产物完整(index.html > 1000B)
└──────────────┘| 层 | 名称 | 运行方式 | 依赖 |
|---|---|---|---|
| L1 | 构建验证 | hexo generate + 产物检查 | 无 |
| L13 | 全量单测门禁 | node tools/tests/*.test.js + shell 单测 | 无 chromium |
| L11 | Playwright 集成 | 真实浏览器 + 本地 server | chromium + server |
| L2/L2b/L2x/L2y/L2i | 生产 URL 断言 | curl + grep | 生产/本地 server |
| L3-L8 | 功能标记检查 | curl + 静态断言 | 生产/本地 server |
| L9 | 静态资源 + SW 冒烟 | curl + playwright | 生产域名 |
| L10 | SW 冒烟(测试域) | playwright | Vercel 测试域 blog2.17lai.site |
2. release-test.sh 用法
# 完整跑(构建 + 生产检查 + SW 冒烟 + playwright 集成)——发版门禁
tools/tests/release-test.sh
# 跳过构建(public/ 已就绪)
tools/tests/release-test.sh --skip-build
# 本地迭代(测 localhost:4000,跳过远程 SW 冒烟 L10 + playwright 集成 L11)
tools/tests/release-test.sh --local
# 仅跳过远程 SW 冒烟(保留 playwright 集成)
tools/tests/release-test.sh --skip-l10| 参数 | 作用 |
|---|---|
--skip-build | 跳过 L1 构建 + 产物验证(已构建时用) |
--local | 目标改 http://localhost:4000,跳过 L10(远程 SW 冒烟 5min+)与 L11(playwright 串行 >800s) |
--skip-l10 | 仅跳过 L10,保留 L11 playwright 集成 |
发版铁律:
tools/cicd.sh -r发布后必须跑tools/tests/release-test.sh验证生产环境。
3. L1-L13 各层覆盖内容
| 层 | 覆盖内容 | 断言示例 |
|---|---|---|
| L1 | 构建验证 | hexo g Success + public/index.html > 1000B |
| L2 | 20 个 layout 页面 URL 可达 | /posts/fc764afd/、/archives/、/categories/、/tags/、/about/、/friends/、/galleries/、/bb/、/musics/、/movies/、/msg/ + 4 篇测试文章 → HTTP 200 |
| L2b | 多语言验证 | en 文章真实翻译 / 回落提示条 / 评论 path 归一化 / 默认语言无前缀 |
| L2x | 统一语言回落 | MATERY_LANG 注入 / 回落页 / 独立页多语言(含 gallery 子页)/ 聚合页多语言 |
| L2y | 加密解密刷新 | wiki 侧栏无 encrypt_ 垃圾标题 / 加密容器完整(hbeForm + storage-key) |
| L2i | SEO 结构化数据 | og:image / JSON-LD / fetchpriority |
| L3 | 评论区检查 | msg/friends/bb 页含 #comments |
| L4 | href=/ 样式错误 | 页面 href=/ 引用数应为 0 |
| L5 | 版本号一致性 | config vs sw.tmp.js 3 处一致 |
| L6 | 关键资源检查 | 404 页面 / 关键 JS 版本 |
| L7 | 核心功能覆盖 | 相册灯箱 / 加密相册 / 搜索 / JS 模块合并 / TOC 折叠 / 暗色 / 评论 / infinite-scroll / wiki 代码块 |
| L8 | 增强功能覆盖 | tag 插件渲染(note/timeline/tabs/label/githubCard/mermaid)/ 加密文章 / Feed / 静态资源 / 分析 |
| L9 | 静态资源 + SW 冒烟 | main.css > 50KB / utils.js > 5KB / 生产域名 7 页无 SW 错误 |
| L10 | SW 冒烟(测试域) | blog2.17lai.site 7 页无 SW 错误 + 交互验证(搜索/打赏/灯箱/TOC/暗色) |
| L11 | Playwright 集成(14 项) | 见下表 |
| L12 | 本地化资源检查 | mermaid / aplayer 资源存在 |
| L13 | 全量单测门禁 | 13 个 .test.js + unit-css-architecture + unit-version + unit-retry |
L11 Playwright 集成清单(真实浏览器)
| 测试文件 | 覆盖 |
|---|---|
effects-integration.test.js | 页面特效(sakura/snowflake/fireworks 加载) |
videobg-integration.test.js | 视频背景(门槛/亮暗池/webm 契约/禁用态) |
wordcloud.test.js | 词云 / 去 jQuery / TOC 防闪烁 / 明暗切换 |
i18n.test.js | 多语言补全(MATERY_I18N 注入 + 按钮文案 + en 翻译) |
musics-integration.test.js | 在线音乐 APlayer(多域名 failover) |
lazyload-integration.test.js | 懒加载 handleCard 三分发(51 断言) |
floating-panel-integration.test.js | 悬浮面板(开关/字体缩放/持久化) |
content-width.test.js | 内容宽度统一(4K/FHD/2K/单栏封顶) |
readmode-integration.test.js | 阅读模式 / 代码全屏(PASS=14) |
core-events-integration.test.js | 事件总线 / 进度条联动 |
wiki-prism-integration.test.js | Wiki 代码块 prism + line-numbers |
misc-interactions.test.js | 打赏弹窗 / 繁简转换(G14/G15) |
lang-client-strategy.test.js | 客户端语言策略(全站跟随/爬虫跳过/面板回显,7 断言) |
rich-content-integration.test.js | 富内容渲染(公式 MathJax+KaTeX/mermaid/markmap/打字机/分享/Live2D,11 断言) |
4. 单测清单(tools/tests/)
L13 门禁单测(release-test.sh 直跑)
# node 单测(纯单测/静态,无浏览器依赖)
unit-toc.test.js # TOC 折叠配置(collapseDepth 0||6 falsy 陷阱)
unit-search.test.js # 搜索三引擎
unit-multilang.test.js # 多语言配置
unit-encrypt2.test.js # 加密扩展(片段 + wiki)
unit-wiki-helper.test.js # wiki helper
lang-fallback.test.js # 回落链 4 级(13 断言)
echarts-charts.test.js # ECharts 图表
banner-bg.test.js # banner 与背景偏好联动
homepage.test.js # 首页结构
imgsize-unit.test.js # 图片尺寸
search-integration.test.js
infinite-scroll-aos.test.js
unit-standalone.test.js # 独立页排除法判定 + 语言前缀豁免(22 断言)
# shell 单测
unit-css-architecture.test.sh # CSS 架构(编译产物关键选择器)
unit-version.test.sh # 版本递增进位(防 12.99→12.100)
unit-retry.test.sh # 退避重试库其他单测(run-tests.sh L1 / L8 段)
unit-encrypt.test.js # 自研加密体系(AES-GCM + PBKDF2 闭环,9 用例)
unit-fontawesome.test.py # FontAwesome 精简脚本5. 外部依赖重试与降级(lib/retry.sh)
第三方网络抖动不可避免(Algolia API / CDN 视频 / 音乐 API),且外部服务不可用不是产品缺陷,不应拦发版。tools/tests/lib/retry.sh 统一处理:
source tools/tests/lib/retry.sh
# exit-code 判定:退避重试 3 次(1s/4s/9s + 抖动)
retry_run "L2 搜索" "node tools/tests/search-integration.test.js"
# 输出模式判定(release-test L11 用)
retry_match "L2d 视频" "node .../videobg-integration.test.js" "PASS=.*FAIL=0"失败分类(全失败时按日志签名区分):
| 签名 | 判定 | 结果 |
|---|---|---|
ERR_NAME_NOT_RESOLVED / ECONNREFUSED / ETIMEDOUT / 429 / 50x 等 | 外部不可用 | ⚠️ 降级 warn(返回 0,不拦发版) |
| 无外部签名 | 业务断言失败 | ❌ fail(返回 1,真 bug) |
6. 第三方拦截 + ERR_ABORTED 排除(lib/browser-env.js)
playwright 测试的共享环境辅助,统一"页面自身错误"归属:
const { interceptThirdParty, collectPageErrors } = require('./lib/browser-env');
const env = collectPageErrors(page, BASE); // 持续累积 JS 异常 + 同源资源失败
await interceptThirdParty(page); // 拦截已知污染源
// 断言:env.jsErrors.length === 0 && env.sameOriginFailures.length === 0| 机制 | 说明 |
|---|---|
interceptThirdParty | 拦截已知污染源(如 webpushr 返回非 JSON → 页面 unhandled rejection),返回合法 JSON 而非 abort(abort 会产生 net::ERR_FAILED 反成新噪声) |
collectPageErrors | 仅收集 JS 异常 + 同源(localhost/生产域)资源失败;第三方 CDN/图床失败为环境噪声不计入 |
ERR_ABORTED 排除 | 导航中断(多次 goto/离开页面取消在途请求)非资源错误,直接跳过 |
7. 压缩开关验证(cicd.sh)
tools/cicd.sh 按模式注入压缩开关(sed 替换根 _config.yml 的 # minify-switch 标记行):
| 模式 | minify 值 | 说明 |
|---|---|---|
-d / --debug | false | 不压缩(本地调试,产物可读) |
-r / -c / -t | true | 压缩(hexo-minify 在 generate 时恒压缩,故需改其 enable) |
验证方法:
# 1. debug 构建(未压缩)
tools/cicd.sh -d
head -c 300 public/css/main.css # 多行、带缩进、有注释
# 2. 压缩构建(-t 本地编译测试,压缩无 CDN)
tools/cicd.sh -t
head -c 300 public/css/main.css # 单行、无注释、体积显著变小构建后 cicd.sh 会还原
_config.yml(仅当改动只涉及 minify-switch 标记行时),避免工作区脏。
8. 如何新增一个测试用例
步骤
- 确定测试类型:
- 纯单测 / 静态断言(无浏览器)→ 归 L13(node 直跑)
- playwright 集成(需 chromium + server)→ 归 L11
- 创建测试文件
tools/tests/xxx.test.js(node:test 或 playwright) - 外部依赖测试:用
retry_run/retry_match包装(lib/retry.sh),全失败自动分类降级 - playwright 测试:用
lib/browser-env.js的interceptThirdParty+collectPageErrors统一错误归属 - 注册到 release-test.sh 对应层(L11 或 L13 段),输出格式对齐(
PASS=N FAIL=0或N 通过 / 0 失败) - 本地验证:
tools/tests/release-test.sh --local(跑 L13 + curl 断言);发版门禁跑全量
断言输出约定
release-test.sh 按输出模式判定通过/失败,测试文件末尾必须输出可匹配的汇总行:
console.log(`\n结果: PASS=${pass} FAIL=${fail}`);
process.exit(fail > 0 ? 1 : 0);测试用例权威清单
docs/superpowers/specs/2026-08-06-layout-test-cases.md(全量 layout 测试用例)+ docs/testing/TESTING-PYRAMID-GUIDE.md(测试方法论)——新增功能后同步更新用例清单与 release-test.sh 覆盖。
附:测试体系速查表
| 命令 | 用途 |
|---|---|
tools/tests/release-test.sh | 发版全量门禁(L1-L13) |
tools/tests/release-test.sh --local | 本地迭代(跳 L10/L11) |
tools/tests/run-tests.sh | 搜索系统测试一键运行(L1 单测 + L2 集成) |
tools/tests/run-tests.sh --unit-only | 仅单元测试 |
make test-pwa | Vercel 测试域 SW 冒烟(7 页)+ 交互验证 |
make visual-compare / visual-assert | 视觉回归(playwright 数值断言) |
tools/visual-regression.sh report | 视觉对比报告(20 页面 × 4 断点) |

