Hexo主题功能测试-自动化测试篇
本文是 matery 主题自动化测试体系的完整教程,与其余 4 篇功能测试文章(内容 tag / 交互视觉 / 布局页面 / Markdown 语法)配套——那 4 篇是"测试靶场",本文是"测试引擎"。权威依据:tools/tests/release-test.sh(L1-L14,13 层 156 行纯编排)、docs/superpowers/specs/2026-08-06-layout-test-cases.md。
基址:生产固定 https://blog.17lai.site(443,绝无端口);本地 LOCAL_BASE 走端口自适应——探测顺序 BLOG_PORT 环境变量 → TEST_BASE 环境变量 → 根 _config.yml 的 server.port(docker 4000)→ 4100,取第一个 HTTP 200;成功后导出 TEST_BASE/TEST_URL,36 个测试文件自动跟随。
执行顺序(156 行纯编排,非文档顺序):L0 preflight → L10 → L01 → L02 → L03_05 → L07 → L08 → L09 → L11 → L12 → L2i → L13 → L13a → L14 → TC 索引校验 → 汇总。注意 L10 最先跑(在 L01 之前)——旧文档常写反。
发版铁律:tools/cicd.sh -r 发布后必须跑 tools/tests/release-test.sh 验证生产环境。
第三方网络抖动不可避免(Algolia API / CDN 视频 / 音乐 API),且外部服务不可用不是产品缺陷,不应拦发版。tools/tests/lib/retry.sh 统一处理:
playwright 测试的共享环境辅助,统一"页面自身错误"归属:
tools/cicd.sh 按模式注入压缩开关(sed 替换根 _config.yml 的 # minify-switch 标记行):
构建后 cicd.sh 会还原 _config.yml(仅当改动只涉及 minify-switch 标记行时),避免工作区脏。
门禁前先过 preflight(环境预检,step 0),未就绪则秒级失败并打印修复命令,避免"跑一半才发现 server 挂了":
--prepare 自动就绪:容器未跑则启动、产物无效则重建、最后复检。
单实例锁:门禁启动即在 ${TMPDIR:-/tmp}/opencode/gate.lock 取锁,并发运行被直接拒绝(打印持锁 PID);陈旧锁自动接管,trap EXIT 释放。禁止并发门禁——并发会互相 kill 本地 server。
基址与端口自适应:见 §2 的基址段(生产 443 固定 / 本地端口探测)——36 个测试文件靠导出的 TEST_BASE/TEST_URL 自动跟随。
tools/visual-assert/*.json 共 16 套件,门禁 L14 只跑其中 7 套:layout-checks、dark-mode、search-modal、reward-modal、homepage、about、footer。
⚠️ make visual-assert 陷阱:该 make 目标依赖 build,build 会原地改写 themes/matery/_config.yml 占位符 → 触发 L5 版本一致性 4 项失败。正确用法:node tools/visual-assert.js run --local [tools/visual-assert/<suite>.json],或交给 L14 层跑。
测试的权威来源是 tools/tests/**;生成的 TC 表位于 docs/superpowers/specs/2026-08-06-layout-test-cases.md 的 <!-- GENERATED:START --> 与 <!-- GENERATED:END --> 之间。
首次克隆需启用一次:git config core.hooksPath .githooks。门禁报"TC 清单不一致"时,跑 make tc-index 再提交(旁路 git commit --no-verify)。
当前索引:13 层 / 33 测试文件 / 3 lib 文件 / 251 断言 / 84 用例名。
flake 可见化:被重试后通过的项目记入 FLAKY_LIST,门禁末尾打印 ⚠️ 本次门禁 flaky: N 项(…);它不改变 PASS/FAIL 计数,只让抖动可见。
具体 PASS 条数随版本增长(每新增一条断言即变化),以实际输出为准,不写死数字。
3 个 lib:assert.sh(82 行)、retry.sh(114 行,负责 flake 追踪)、preflight.sh(230 行)。browser-env.js 为 playwright 共享辅助(见 §6)。
已知覆盖缺口:wiki-integration.test.js、infinite-scroll-integration.test.js 两个文件存在但未挂入任何层(纯 playwright,无浏览器时必失败;由 L11 或发版前手动 playwright 验证覆盖)。新增用例时注意别重蹈覆辙。
写单测 mock site / locals 时,必须贴合 Hexo 的真实对象,否则单测全绿也拦不住构建级故障:
教训:mock 越接近真实对象,单测才越能拦住构建级故障;用普通数组替代 Query 会测不出 toArray() 缺失。
L13 单测模板(node:test,无浏览器依赖):
L11 playwright 模板(需 chromium + server):
L13(node 单测):在 release-test.sh 的 ## L13 段追加一行:
L11(playwright 集成):在 release-test.sh 的 ## L11 段追加:
retry_match 包装外部依赖测试——网络抖动时自动重试 3 次,全失败降级为 warn 而非 fail(见 §5)。
release-test.sh 按输出模式判定通过/失败,测试文件末尾必须输出可匹配的汇总行:
docs/superpowers/specs/2026-08-06-layout-test-cases.md(全量 layout 测试用例)+ docs/testing/TESTING-PYRAMID-GUIDE.md(测试方法论)——新增功能后同步更新用例清单与 release-test.sh 覆盖。
性能指标(LCP)不在自动化门禁内——它需要 Lighthouse 真机采样 + 网络条件控制,断言型测试无法稳定表达。验证方式是基线文档 + 复现命令:
原因:本地预览使用旧缓存产物,测试断言的是旧版行为。
正确做法:跑门禁前必须 npm run clean && npm run build,或使用 tools/tests/release-test.sh --prepare 自动就绪。
现象:修改友链/相册数据后,L2 URL 断言页面空白或数据不更新。
正确做法:修改数据文件后先 rm -f db.json && npm run build 再跑门禁。容器环境用 tools/cicd.sh -d(内置 clean)。
用途:想知道"某个功能有没有被自动测试覆盖"?在这里按功能名查找。
新增/修改一篇「hexo主题功能测试」系列文章时,检查以下三项:
快速判断:如果一个功能"只列了名字没说怎么验证"→ 缺 ①;"只列语法不给效果"→ 缺 ②;"没说怎么用或有歧义"→ 缺 ③。