AI 改完页面后,浏览器验收不能省

0阅读10分钟

Typecheck 通过 ≠ 页面能用

我在过去半年的 AI 编程实践中,反复遇到同一类问题:Agent 写完代码,跑通 typecheck,跑过单测,报告「已完成」。但打开浏览器一看——响应式溢出、hydration 错误、资源 404、交互状态断裂——这些没有一个能被 typecheck 或单测捕获。

代码产出越快,这个缺口越大。Autonoma 的研究指出 AI Agent 的代码产出量是人工的三个数量级,而浏览器验收是补上这个缺口最直接的手段。

GitLab 的前端测试规范里有一句话值得贴出来:

"There's always the chance of accidentally breaking the user flow, while the tests pass and provide a false sense of security."

GitLab Frontend Testing Standards

haikumethod.ai 的一篇复盘记录了一个具体的案例:CI 绿灯,单测全过,代码审查签字——页面还是坏的。多步工作流的所有检查都通过了,但最终界面上新增的 UI 元素根本没渲染出来。问题不在于代码写错了,在于整个流程里没有一层检查在打开浏览器看结果。

AI 编程时代,浏览器层的缺口

传统开发中,工程师写完代码会习惯性地在浏览器里点两下——这是肌肉记忆。AI 编程打破了这个循环:Agent 不打开浏览器,它的「完成」定义是 typecheck + test pass。当你依赖 Agent 产出代码,同时又省略了人工浏览器检查这一步,质量缺口就出现了。

下表列出了 AI 生成代码在浏览器层常见的盲区:

问题类型具体表现Typecheck 能捕获单测能捕获
响应式溢出移动端按钮被挤出视口、文字换行断裂
Hydration 不一致SSR 输出与客户端初始渲染不同,控制台报红部分
资源加载失败图片 404、字体回退、SVG 不显示
布局遮挡固定定位元素覆盖可交互区域
交互状态断裂点击后状态未更新、URL 未变化部分部分
控制台异常未捕获 Promise rejection
视觉回归按钮颜色变了、间距不一致

Typecheck 能覆盖的场景,全部是编译期可推导的;用户在浏览器里遇到的问题,绝大多数发生在运行期。A Modern Quality Pipeline 一文中将这种思路总结为「分层置信」——每一层检查只负责它能抓到的问题,越靠近用户感知的层越贵,但也能抓到越底层抓不到的东西。

流程图画布 · 115%
Mermaid 流程图加载中...

浏览器验收是质量流水线的最后一道闸门。前面的层越严格,浏览器验收时需要修的越少;但无论前面多严格,浏览器验收都不能跳过。

五个验收层面

一、首屏渲染

首屏渲染是用户形成第一印象的窗口。页面白屏超过 3 秒、骨架屏卡住不消失、关键图片裂开——用户不会等你 debug。

AI 生成代码在首屏渲染上常见的坑:

  • 数据请求路径断裂:Agent 写了 useEffect 请求数据,但 API 路径拼错或环境变量没传进去,请求 404,页面拿到空数据后渲染空白。
  • 骨架屏永远不消失:骨架屏的消失条件依赖某个 loading 状态变量,但 Agent 改动了数据获取逻辑后忘了更新这个状态。
  • 动态导入失败next/dynamic 引用了不存在的组件路径,构建能过(因为 dynamic 是运行时加载),但页面直接白屏。

验收脚本的核心逻辑并不复杂——打开浏览器,导航到目标 URL,收集网络错误和控制台错误,截图存档:

// 首屏验收的核心判定
const pass = firstPaint < 3000              // 3 秒内完成
  && networkErrors.length === 0             // 无 4xx/5xx
  && !consoleErrors.some(e =>               // 无 hydration 错误
    e.includes('hydration')
  )

任何一条不满足,passfalse,需要回传 Agent 修复。完整实现可以用 Playwright 的 page.on('response')page.on('console') 事件收集错误,page.screenshot() 截图存档。

二、关键交互

静态截图能抓布局,但抓不到交互逻辑。AI 生成代码的交互问题往往比布局问题更隐蔽。

我在一个分页组件上遇到过这类问题:Agent 实现了一个分页列表,桌面端截图完美,单测通过(因为单测 mock 了数据)。但在浏览器里点击「下一页」,列表内容更新了,页面滚动位置没变——用户看到的是第二页数据的底部,以为没有反应。

这个问题的根因是 Agent 没有加 scrollTo 逻辑。类型系统不会告诉你「翻页后应该滚回顶部」,这是用户交互经验。

验收脚本需要模拟真实用户操作序列:

// 分页交互验收的核心逻辑
const firstItemBefore = await page
  .locator('[data-testid="list-item"]').first().textContent()
 
await page.locator('[data-testid="next-page"]').click()
await page.locator('[data-testid="list-item"]').first().waitFor({ state: 'visible' })
 
const firstItemAfter = await page
  .locator('[data-testid="list-item"]').first().textContent()
 
// 验证内容已更新
if (firstItemBefore === firstItemAfter) {
  throw new Error('分页点击后内容未更新')
}
 
// 验证页面滚回顶部
const scrollAfter = await page.evaluate(() => window.scrollY)
if (scrollAfter > 100) {
  throw new Error(`分页后页面未滚回顶部,当前滚动位置: ${scrollAfter}px`)
}

Agent 写单测时通常只验证内容是否更新,滚动位置这类体验细节需要浏览器验收来补。

三、响应式布局

根据 StatCounter 的数据,2026 年全球移动流量占比稳定在 60% 以上。但 AI 生成 UI 代码时,默认优化的往往是桌面端——训练数据中桌面端示例更多,Agent 的截图工具也默认用桌面视口。

检查维度桌面端(1440px)移动端(375px)常见 AI 生成问题
导航栏水平菜单汉堡菜单缺少移动端折叠逻辑
列表布局多列 Grid单列 StackGrid 不降列,横向溢出
弹窗/抽屉居中 Modal底部 SheetModal 在小屏被键盘遮挡
表格完整展示横向滚动或卡片化表格撑破容器

响应式验收的核心是多视口检测水平溢出

// 水平溢出检测——AI 代码最常见的响应式问题
const hasHorizontalOverflow = await page.evaluate(() => {
  return document.documentElement.scrollWidth > window.innerWidth
})

scrollWidth > innerWidth 这一个判断就能抓住大部分 AI 生成的响应式问题。桌面端写的 min-width: 1200px 容器在 375px 屏幕上不会自动收缩,直接把页面撑出横向滚动条。建议至少在 1440px、768px、375px 三个视口各跑一次。

四、控制台错误

控制台错误是开发者的早期预警。忽略控制台错误,等于对着一堆告警灯选择性地不看。

错误类型典型信息影响程度
Hydration 错误Text content did not match高——可能导致交互失效
资源加载失败GET .../image.png 404中——用户看到破碎图标
CORS 错误blocked by CORS policy高——数据完全无法加载
未捕获异常Unhandled Promise Rejection高——可能导致页面白屏
React Key 错误Each child should have a unique "key"中——列表更新时渲染错乱
Deprecated API... is deprecated低——当前可用但未来会坏

验收时的关键做法是错误分级:Hydration 错误、网络失败、未捕获异常是 critical——必须修复才能通过;React key 警告是 warning——应该修但不阻塞;deprecated API 是 info——记录下来即可。给 Agent 回传修复指令时,只传 critical 错误,避免噪音淹没有效信息。

五、视觉回归

前四个层面关注功能正确性,视觉回归关注「看起来对不对」。AI 改代码时经常产生意外的视觉变更——按钮颜色变了、间距宽了、字体从 Inter 降级到了 system-ui——这些不影响功能,但用户会觉得「页面变了」。

2026 年的视觉回归测试工具链已经相当成熟:Chromatic、Percy、Applitools、Lost Pixel 等工具可以在 CI 中自动对比截图,标记像素差异。Delta-QA 的 2026 前端测试指南建议每个关键页面维护 2-3 组视觉基准截图,覆盖不同设备和交互状态。

对于 AI 编程场景,视觉回归的价值在于给 Agent 提供一个可回传的对比证据。Agent 说「已完成」,你跑一次视觉对比,发现按钮从蓝色变成了绿色——把差异截图丢回给 Agent,它就能定位是哪段 CSS 改动导致的。

四个真实案例

案例一:消失的筛选器

让 Agent 给商品列表页增加价格筛选功能。Typecheck 和单测全过——筛选组件的 props 类型正确,onChange 回调的 mock 验证通过。

浏览器验收发现:切到 375px 移动端视口,筛选器被 overflow: hidden 裁掉了。更严重的是,Firefox 下筛选器的 &lt;input type="range"&gt; 滑块完全无法拖动,因为 Agent 用了 WebKit 私有的 CSS 属性。

根因:Agent 的训练数据以 Chrome 为主,跨浏览器兼容性不在它的默认关注范围内。固定高度容器是复制了另一个组件的样式。

修复:移除 overflow: hidden,改用 min-height + flex-grow;range input 用标准属性替换 -webkit-slider-thumb

案例二:无限循环的请求

让 Agent 实现搜索建议组件,输入时显示联想词。Typecheck 和单测全过——防抖逻辑的单测验证了 300ms 延迟后触发请求。

浏览器验收发现:控制台每 300ms 发出一次相同的 API 请求,即使输入内容没变。Agent 把输入值放在了 useEffect 的依赖数组里,但 useEffect 内部每次都创建新的请求对象(引用不同),触发父组件 re-render,导致输入值引用变化,又触发 useEffect。控制台里还有一条 Maximum update depth exceeded 警告。

根因:循环依赖——useEffect → 状态更新 → re-render → useEffect。JSDOM 单测很难复现,因为 JSDOM 的 render 生命周期和真实浏览器不同。

修复:用 useRef 缓存上一次的查询值,只在值变化时发请求。

案例三:桌面完美、移动端崩溃的表格

让 Agent 给后台管理系统加一个用户数据表格。Typecheck 和单测全过。

浏览器验收发现:1440px 下表格完美展示 8 列数据。切到 375px,表格直接撑出 1200px 宽,操作列(编辑/删除按钮)被挤到视口外面。

根因:Agent 用了 display: grid; grid-template-columns: repeat(8, 1fr),没有加任何响应式断点。

修复:移动端用卡片布局替代表格,或 overflow-x: auto 加首列固定。

案例四:暗色模式下的隐形文字

让 Agent 实现暗色模式切换。Typecheck 和单测全过。

浏览器验收发现:切换到暗色模式后,一个 Alert 组件的文字变成了深灰色(#333),背景也是深灰色(#2d2d2d)——文字完全看不见。这个 Alert 组件用了硬编码的颜色值,没有走 CSS 变量。

根因:Agent 生成新组件时用了硬编码颜色,没有复用项目已有的 design token 系统。Typecheck 不检查颜色值是否适配主题,单测也不渲染暗色模式的上下文。

修复:将所有硬编码颜色替换为 CSS 变量(var(--color-text-primary))。

完整验收清单

五个层面检查完,整理出一份可直接使用的验收清单。可以交给 Agent 当验收标准,也可以人工当 checklist 用。

桌面端(1440px / 1280px)

#检查项通过标准优先级
1首屏渲染3 秒内完成,无白屏/骨架屏卡住P0
2网络请求无 4xx/5xx 响应P0
3关键交互本次改动相关的按钮/链接/表单正常工作P0
4状态更新交互后列表刷新、URL 变化、反馈提示正确P0
5Hydration控制台无 hydration 错误P0
6资源加载图片、字体、图标全部正常显示P1
7布局完整无元素溢出、重叠、截断P1
8视觉一致与基线截图差异 < 0.5%P1

移动端(375px / 414px)

#检查项通过标准优先级
1水平溢出scrollWidth 不超过 innerWidthP0
2触控目标按钮/链接最小 44x44pt,间距 ≥ 8pxP0
3文字可读无溢出、截断、字号过小(≥ 12px)P0
4导航可用汉堡菜单可展开,导航链接可点击P0
5弹窗适配Modal/Sheet 不被键盘遮挡,可关闭P1
6图片缩放max-width: 100% 生效,不撑破容器P1
7表格/横向内容横向滚动或卡片化降级正常P1

通过标准:P0 项全部通过 → 验收通过,可以合并。P0 有失败 → 回传 Agent 修复。仅 P1 失败 → 记录为技术债,可合并但需跟进。

把验收指令写给 Agent

手动做浏览器验收太繁琐,也容易漏项。更靠谱的做法是把验收标准写成指令,让 Agent 自己跑浏览器验收——给它明确的 URL、视口、检查点和期望行为。

启动本地服务(pnpm dev),等待 http://localhost:3000 可访问后:

1. 桌面端验收(viewport 1440x900)
   - 打开 /blog,等待 networkidle
   - 截图保存到 verify-screenshots/desktop-blog.png
   - 检查控制台是否有 hydration 错误或网络 4xx/5xx
   - 点击分页组件的「下一页」按钮,确认列表内容更新且页面滚回顶部

2. 移动端验收(viewport 375x812)
   - 打开 /blog,等待 networkidle
   - 检查是否有水平溢出(scrollWidth > innerWidth)
   - 截图保存到 verify-screenshots/mobile-blog.png
   - 确认分页按钮可见且可点击(最小触控区域 44x44)

3. 如果任何检查失败,将错误信息和截图写入 FIX_REPORT.md,然后修复后重新验收。

这份指令覆盖了五个层面中的四个(首屏、交互、响应式、控制台),加上截图作为证据。视觉回归需要基线截图对比,可以在基础验收稳定后再加入。

从人工到自动化

每次手动开浏览器点不现实。把检查集成到 CI 流水线,AI 生成代码后自动跑,才是可持续的做法。

阶段触发时机浏览器验收内容工具
本地开发Agent 完成代码后快速首屏检查 + 控制台错误扫描Playwright 脚本
PR 提交CI 构建成功后多视口截图 + 关键交互验证Playwright + Preview Deploy
Preview URL预览部署完成后视觉回归 + 完整交互流程Chromatic / Percy
合并前人工 review 时人工抽查 + 截图对比浏览器 DevTools

核心原则是越早发现问题,修复成本越低。Agent 在本地写完代码就应立即跑一次浏览器验收,不要等到 CI 或 PR 阶段才第一次打开浏览器。

# .github/workflows/browser-verify.yml
name: Browser Verification
 
on:
  pull_request:
    paths: ['apps/**', 'packages/ui/**']
 
jobs:
  browser-verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22, cache: pnpm }
      - run: pnpm install --frozen-lockfile
      - run: pnpm build
      - run: pnpm preview &
      - run: npx wait-on http://localhost:3000 --timeout 30000
      - run: pnpm tsx scripts/browser-verify.ts
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: browser-verify-screenshots
          path: verify-screenshots/

构建 → 启动预览服务 → 跑浏览器验收脚本 → 上传截图。验收失败阻塞 PR 合并,截图作为 Artifact 上传供人工查看差异。

收束

浏览器验收是前端质量流水线的最后一道闸门。Typecheck 验证代码声明,单测验证函数逻辑,E2E 验证用户流程——但只有浏览器验收在验证用户实际看到和体验到的东西。

AI 编程时代,代码产出速度在加快,浏览器层的验证没有自动跟上。Agent 不会主动打开浏览器,它的「完成」标准是 typecheck + test pass。如果不显式要求浏览器验收,质量缺口会随着 AI 产出量的增加而扩大。

核心思路:

  1. 把验收标准写成可执行的脚本——Playwright 截图 + 错误收集 + 视口检测
  2. 把验收指令写给 Agent——明确 URL、视口、检查点、期望行为
  3. 把验收集成到 CI——PR 提交后自动跑,失败阻塞合并
  4. 用截图做证据——以截图为准,以主观感受为辅

下次让 AI 改完页面后,不要只看 typecheck 输出。花 5 分钟做一次浏览器验收——或者让 Agent 自己做,然后看截图确认。


参考资料

评论 0

0 / 1000