跳到正文

测试

不用安装测试框架,也不用写配置:所有测试都是跑在公开入口上的普通 Node 脚本。

npm run lint          # ESLint,flat config
npm test              # 纯函数单测
npm run test:build    # 构建 fixture 站点并断言产物
npm run test:browser  # 在 Chromium 中实跑构建产物
npm run test:all      # 以上四层按序全跑

npm run test:browser 有两步前置:

npx playwright install chromium   # 一次即可
npm run test:build                # 先构建 fixture,每次改完源码都要重来

浏览器层不会替你构建。 产物比 src/ 旧时它会直接报错退出,而不是拿上一次的产物 跑出一片绿 —— 否则「改了主题再跑浏览器层」永远测的是旧代码。

各层分别拦什么

层文件拦的问题
Linteslint.config.js无用代码、Vue 模板写法错误
单测scripts/test.mjs纯逻辑错误:链接解析、slug、locale 匹配、标题树、阅读时间与字数
集成scripts/test-build.mjs接线错误:页面生成到了错误的 locale 下、链接指向没人创建的路由、标签链接逃出自己的 locale、分页页数两端不一致
浏览器scripts/test-browser.mjs运行时错误与位置错误:hydration 不一致、导航栏不吸顶、锚点落点在导航栏下方、目录高亮慢一格、重复/不可达的控件、抽屉不响应 Escape、配色图标与已绘制主题不符、组件名解析失败(只在 console 里,构建日志看不见)

分层是刻意的。构建打印 success 也可能生成了一个没人链接的页面;链接正确的页面也可能 在客户端抛错;而没注册的组件既不会让构建失败,也不会产生坏链接 —— 它只在浏览器 console 里留下一行 warning,页面上那块是空的。1.5.0 修的 WCardList/WSteps 就是这一类。

更难的一类是元素都在、位置全错:粘性导航栏失效、锚点落点偏了一个导航栏的高度、 目录高亮慢一格。它们的 HTML 完全正确,静态检查全绿,只有把产物放进真浏览器、逐项量 getBoundingClientRect() 才看得见。浏览器层因此不只看「有没有元素」,还看 在哪里、可不可达、有几个。

当前规模:单元 26、集成 26、浏览器 28。

fixture 站点

test/i18n/ 是一个小站点,含一个嵌套 locale,并且挪走了自己的博客。这个形状刻意做得 别扭,因为它正是会压坏 locale 处理的形状:

test/i18n/docs/
├── posts/          # 4 篇英文文章,标签:shared / english / math / C++
├── guide/          # 含一个 js fence、一个无语言 fence
└── zh/
    ├── posts/      # 2 篇文章,标签:shared / C++ / 中文标签
    └── guide/

站点配置刻意做得别扭:每页 2 篇文章(于是分页与标签分页都会被压到)、关掉两个代码高亮器 (于是代码块是「没有包装元素」的那种形状)。

集成测试断言的其中几条:

  • 根 locale 列表不含中文文章,尽管 /zh/posts/one.html 同样以 / 开头
  • shared 在两个 locale 中都存在,内容各不同,而不是一方偷走另一方的归档
  • C++ 与非 ASCII 标签各自得到一个可访问的归档
  • 主页与标签页都被分页,且每个被链接的页数都真的存在
  • 每个生成页面里的每个内链都指向真实存在的路由
  • 站点里每一个 /tags/… 链接都指向已生成的页面
  • 某个 locale 内的标签链接永不指向另一个 locale 的归档
  • ClientOnly 里的东西(页内目录、进度条)不在服务端 HTML 里
  • 组件正文被渲染成 markdown,而不是原样输出作者写的源码
  • WSteps 的序号在服务端产物里正确递增
  • 文章以 <time> 元素展示日期,并显示阅读时间

浏览器测试另加:

  • 代码块有语言标签,点复制真的把片段(不是按钮文案)写进剪贴板
  • 没有语言的 fence 有按钮、没有标签
  • 进度条从 0 跟到 ≥0.9
  • 抽屉打开后焦点移入、连按 40 次 Tab 都不逃出去、关闭后焦点还给按钮
  • Escape 关下拉但不关抽屉
  • /zh/ 下的侧边栏与导航链接都留在 /zh/ 内
  • 滚动后导航栏停在 top: 0(不吸顶会读到负值)
  • 页内目录的每一项:标题落在粘性导航栏下方 且 不会低到读不出是哪一节
  • 高亮与读者所在章节一致 —— 直接按标题自己的锚点落点滚动,因此差几个像素就会红
  • 320px 到 1920px 之间,没有任何元素被挤出视口(跳过自己有滚动条的代码块与表格), 且导航栏里的每个可见控件都在视口内
  • 全站恰好一个返回顶部控件
  • 首页、博客、404 都有 main#github-main-content,skip link 真的能跳进去
  • WSteps 的序号在服务端产物里就是 1/2/3/4,不是 hydration 之后才改正
  • 站点里不存在嵌套的 <a>
fixture 要够长
进度条这类「页面短就看不见」的功能,短页面根本测不出来。位置类断言更需要长页面: 文档比视口还短时,最后一个标题永远在屏幕上,高亮只能报它 —— 「差一格」这种 bug 在短页面上根本不存在。所以 fixture 里有一篇专门的 guide/long.md。
别用 scrollWidth 判断溢出
overflow-x: hidden 会把 scrollWidth 一起截断,于是被挤出右边缘的控件不会 让断言失败。要遍历所有渲染盒,跳过「自己有滚动条」的容器(代码块、宽表格是应该能 横向滚的)。

测试你自己的改动

scripts/test.mjs 是一串扁平的 test('名称', fn) 调用,加一条用例就是一行。优先测试 纯函数而不是组件:「能用」与「看起来能用」的分界线通常就是一个小函数,而它们正是 fixture 站点端到端压到的东西。

发布前的完整检查清单见发版 —— 四层测试只是其中一步, npm pack 的消费者实测同样不能省。