Skip to main content
Cypress应用

调试

info
你将学到
  • 如何在 Cypress 测试中使用 debugger.debug()
  • 如何使用 .pause() 逐步执行测试命令
  • 如何使用开发者工具获取命令信息的控制台日志
  • Cypress 中错误如何显示和结构化
  • 如何调试不稳定的测试

使用 debugger

你的 Cypress 测试代码与应用程序运行在同一个执行循环中。这意味着你可以访问页面上运行的代码,以及浏览器提供给你的功能,如 documentwindowdebugger

像往常一样调试

基于这些特性,你可能会想在测试中插入一个 debugger,如下所示:

it('let me debug like a fiend', () => {
cy.visit('/my/page/path')

cy.get('[data-testid="selector-in-question"]')

debugger // 不会生效
})

这可能不会如你预期的那样工作。正如你在 Cypress 简介 中所记得的,cy 命令会将操作排队等待后续执行。你能看出上述测试在这种视角下会做什么吗?

cy.visit()cy.get() 都会立即返回,将它们的工作排队等待后续执行,而 debugger 会在任何命令实际运行之前执行。在使用 cy.mount() 的组件测试中,预期会有相同的行为。

让我们使用 .then() 在命令执行时介入,并在适当的时候添加 debugger

it('let me debug when the after the command executes', () => {
cy.visit('/my/page/path')

cy.get('[data-testid="selector-in-question"]').then(($selectedElement) => {
// 在 cy.visit 和 cy.get 命令完成后触发 debugger
debugger
})
})

现在我们可以正常工作了!当你首次访问页面或挂载组件时(如上所示,使用 cy.get() 链及其附加的 .then()),命令会被 Cypress 排队执行。it 代码块退出后,Cypress 开始工作:

  1. 在端到端测试中,页面被访问,Cypress 等待其加载。或者在组件测试中,组件被挂载并渲染。
  2. 查询元素,如果未立即找到,Cypress 会自动等待并重试几次。
  3. 传递给 .then() 的函数被执行,并将找到的元素传递给它。
  4. .then() 函数的上下文中,debugger 被调用,暂停浏览器并将焦点转移到开发者工具。
  5. 你可以开始了!像平常在应用程序代码中插入 debugger 一样检查应用程序的状态。

使用 .debug()

Cypress 还提供了一个调试命令的快捷方式 .debug()。让我们用这个辅助方法重写上面的测试:

it('let me debug like a fiend', () => {
cy.visit('/my/page/path')

cy.get('[data-testid="selector-in-question"]').debug()
})

当前由 cy.get() 产生的主题会在你的开发者工具中作为变量 subject 暴露,以便你可以在控制台中与之交互。

调试主题

使用 .debug() 快速检查测试过程中应用程序的任何(或许多!)部分。你可以将其附加到任何 Cypress 命令链上,以查看系统在该时刻的状态。

逐步执行测试命令

你可以使用 .pause() 命令逐步执行测试命令。

it('adds items', () => {
cy.pause()
cy.get('[data-testid="new-todo"]')
// 更多命令
})

这允许你在每个命令后检查 Web 应用程序、DOM、网络和任何存储,以确保一切按预期进行。

使用开发者工具

尽管 Cypress 已经构建了 一个出色的应用程序 来帮助你理解应用程序和测试中发生的事情,但没有什么可以替代浏览器团队在其内置开发者工具中所做的出色工作。再次,我们看到 Cypress 顺应现代生态系统的潮流,尽可能利用这些工具。

info

观看实际操作!

你可以在 我们 React 教程系列的这个片段 中看到从 Cypress 调试一些应用程序代码的演示。

获取命令的控制台日志

Cypress 的所有命令在 命令日志 中点击时,都会打印关于命令、其主题及其产生结果的额外信息。尝试在打开开发者工具的情况下点击命令日志!你可能会在这里找到一些有用的信息。

点击 .type() 命令时,开发者工具控制台输出以下内容:

控制台日志类型

错误

有时测试会失败。有时我们希望它们失败,只是为了知道它们在通过时测试的是正确的事情。但其他时候,测试会无意中失败,我们需要找出原因。Cypress 提供了一些工具来帮助使这个过程尽可能简单。

错误的结构

让我们通过一个失败的测试来看看错误的结构及其在 Cypress 中的显示方式。

it('reroutes on users page', () => {
cy.contains('Users').click()
cy.url().should('include', 'users')
})

在我们的被测应用程序中,<li>Users</li> 元素的中心被隐藏,因此上面的测试会失败。

当Cypress测试发生错误时,Cypress会打印多条信息。

  1. 错误名称:这是错误的类型(例如AssertionErrorCypressError
  2. 错误信息:通常会告诉你哪里出错了。信息长度不一,有些如示例中那样简短,有些则很长,可能会明确告诉你如何修复错误。
  3. 了解更多:部分错误信息包含了解更多链接,可跳转至相关Cypress文档。
  4. 代码框架文件:通常是堆栈跟踪的顶部行,显示下方代码框架中高亮显示的文件、行号和列号。点击该链接将在首选文件打开工具中打开文件,并在支持的编辑器中高亮显示行和列。
  5. 代码框架:显示失败发生处的代码片段,相关行和列会高亮显示。
  6. 查看堆栈跟踪:点击可切换堆栈跟踪的可见性。堆栈跟踪长度不一。点击蓝色文件路径将在首选文件打开工具中打开文件。
  7. 打印到控制台按钮:点击可将完整错误打印到DevTools控制台。通常允许你点击堆栈跟踪中的行并在DevTools中打开文件。
示例命令失败错误

源映射

Cypress 利用源映射(source map)来增强错误显示体验。堆栈跟踪会被转换,从而显示您的源文件而非浏览器加载的生成文件。这同时支持显示代码框架(code frame)。若没有内联源映射(inline source map),您将无法看到代码框架。

默认情况下,Cypress会在测试规范文件(spec file)中包含内联源映射,因此您能获得最佳的错误显示体验。如果您修改了预处理器,请确保启用内联源映射以获得相同体验。具体示例如下:

如果在自定义预处理器中使用TypeScript,请确保TypeScript编译器生成了源映射。这可以通过在tsconfig.json中将sourceMap选项设为true来实现。不推荐使用inlineSourceMap选项,因为它无法提供准确的代码框架。请参考我们推荐的tsconfig.json配置。

调试不稳定的测试

虽然 Cypress 是 抗不稳定的,但一些用户确实会遇到不稳定的情况,特别是在 CI 中运行与本地运行时。

tip

要调试 CI 中记录的测试的不稳定性,可以尝试使用 Cypress Cloud 中的 Test Replay。它允许你完全按照在 CI 中运行的方式回放测试。

在大多数不稳定的测试案例中,我们看到在进入下一个断言之前,围绕测试操作或网络请求的断言不足。

如果在本地运行与在 CI 中运行时网络请求或响应的速度有任何变化,那么其中一个可能会失败。

因此,我们建议在继续测试之前尽可能多地断言所需的步骤。这也有助于稍后在调试时隔离确切的失败位置。

当本地环境和 CI 环境之间存在差异时,也可能发生不稳定。你可以使用以下方法排查在本地通过但在 CI 中失败的测试。

  • 检查你的 CI 构建过程,确保没有任何更改会导致测试失败。
  • 消除测试中对时间敏感的变异性。例如,在查找依赖于该网络请求数据的 DOM 元素之前,确保网络请求已完成。你可以利用 别名 来实现这一点。

Cypress Cloud 还提供了 Analytics,展示了测试的趋势,并可以帮助识别最不稳定或最常失败的测试。这可能有助于缩小不稳定原因的范围——例如,看到在更改测试环境后失败增加可能表明新环境存在问题。

有关处理不稳定的更多建议,请阅读 我们博客文章系列Identifying Code Smells in Cypress

记录 Cypress 事件

Cypress 会发出多个事件,你可以监听如下所示。 在此处阅读有关在浏览器中记录事件的更多信息

用于调试的控制台日志事件

排查 Cypress 问题

有时你会遇到 Cypress 本身的错误或意外行为。在这种情况下,我们建议查看我们的 故障排除指南

更多信息

通常调试失败的 Cypress 测试意味着更好地理解你自己的应用程序如何工作,以及应用程序如何与测试命令竞争。我们建议阅读这些博客文章,其中我们展示了常见的错误场景及其解决方法: