Skip to content

组件行为、浏览器模式与 CI:练习答案 ​

三层断言的边界可以这样写:

ts
// 纯函数层:无需 DOM
expect(validateEmail('')).toEqual({ ok: false, code: 'empty' })
expect(validateEmail('abc')).toEqual({ ok: false, code: 'invalid' })
ts
// jsdom 层:用户找到控件并观察错误
const input = screen.getByRole('textbox', { name: '邮箱' })
await user.type(input, 'abc')
await user.click(screen.getByRole('button', { name: '登录' }))
expect(screen.getByRole('alert')).toHaveTextContent('请输入有效邮箱')
expect(input).toHaveFocus()
ts
// Browser/E2E 层:真实地址栏和会话
await page.getByRole('textbox', { name: '邮箱' }).fill('user@example.com')
await page.getByRole('button', { name: '登录' }).click()
await expect(page).toHaveURL('/dashboard')
await page.reload()
await expect(page).toHaveURL('/dashboard')

第一条断言验证业务规则,第二条验证 DOM、事件和焦点,第三条验证路由、服务端和浏览器持久化。把第三条塞进 jsdom,通常只能断言 history.pushState 被调用,不能证明真实导航、资源加载和刷新后的会话。

CI 最小脚本示例:

json
{
  "scripts": {
    "test:unit": "vitest run --project unit",
    "test:browser": "vitest run --project browser",
    "test:coverage": "vitest run --coverage"
  }
}

先让 test:unit 独立通过,再运行浏览器项目;不要在 CI 中用 --runInBand 等 Jest 选项猜测并行行为。出现 flaky 时保存重复运行的输入、浏览器版本、trace/截图与首次失败,而不是盲目增加重试次数。

可验证结果:纯函数测试可在 Node 运行;组件测试需要 jsdom;URL 和刷新测试需要 Browser Mode 或 E2E。若环境不具备浏览器,必须把第三层标记为未执行,不能将模拟 DOM 结果当作真实浏览器证据。

用心记录每一步成长