TypeScript 在 Cypress 测试中的所有内容#frontend@twiliosendgrid
已发表: 2020-11-14在 Twilio SendGrid,我们现在使用 TypeScript 和 React 编写大部分前端 Web 应用程序,尤其是新页面和功能,以实现更好的类型检查、可维护性和代码库文档。 两年前我们第一次开始编写 Cypress 测试时,我们的大多数页面对象、帮助程序和规范文件仍然用 JavaScript 实现,而且我们主要使用 Cypress 版本 3.xx 更多最近的测试已经用 TypeScript 编写,但我们仍然有大量文件要转换和迁移到 TypeScript。
我们希望从完全输入我们的组件、单元测试和赛普拉斯 E2E 测试中获益。 自 Cypress 4.4.0 起,迁移到较新版本的 Cypress 以利用 TypeScript 的开箱即用支持使该过程变得更容易。
如果您想退后一步,更一般地了解如何考虑编写 E2E 测试,请随时查看此博客文章。 如果您还想查看我们在不同环境中编写赛普拉斯测试时使用或完成的最常见事情的一千英尺概览,您可以在开始将 TypeScript 添加到赛普拉斯测试之前参考这篇博文。 这篇博文假设您熟悉 Cypress 测试并且之前使用过他们的 API。
如果您准备好了解我们是如何输入内容的,那么让我们先看看一些初始更改,例如如果您来自旧版本,则向 Cypress 添加 TypeScript 支持。
从 Cypress 3.x 迁移到 >= 4.4.0
对于那些已经在 Cypress 版本 3.xx 到 4.4.3 中配置了 Cypress 基础设施以使用 TypeScript 的人,您很可能在plugins/index.js
中设置正确的 Webpack 预处理器配置时经历了一些试验和错误。 对于 Twilio SendGrid 团队来说,存在一些问题,其中某些文件需要是plugins
和support
文件夹中的 JavaScript 文件,并且难以调试的 Cypress 错误会浮出水面。 一旦你得到一些工作,它应该看起来像这样。
从早期版本的 3.xx 升级后,我们能够删除 Webpack 预处理器配置,用index.ts
文件替换我们的plugins/index.js
文件,稍微修改一下 Cypress 文件夹的tsconfig.json
,最后,使用 Cypress 文件夹中的 TS 文件(如some_page.spec.ts
、 index.d.ts
或page_object.ts
)——不再需要 Webpack 预处理器配置,它就可以工作了! 我们很高兴不用管理您自己的 Webpack 预处理器配置并且对我们的文件有更好的 TypeScript 覆盖率,它变得更加简洁和好,如下所示。
在涵盖了 TypeScript 支持之后,我们查看了 Cypress 团队的示例真实世界应用程序 cypress-real-world-app 存储库,以了解更多关于如何更好地键入内容的信息。 我们发现了如何在更新文件时键入cy.task(“pluginName”, { … })
和Cypress.env(“someEnvVar”)
函数调用以更好地链接和键入智能感知支持。 我们还翻阅了他们随附的 TypeScript 文档。 这教会了我们如何键入诸如cy.login()
自定义命令之类的内容,以及如何设置tsconfig.json
配置文件。 示例应用程序还有一个tsconfig.json
供您参考,它可以为您提供一个很好的基础 TypeScript 配置,供您根据自己的喜好进行自定义。 我们建议您及时了解最新的赛普拉斯版本,深入了解赛普拉斯官方资源,并尝试使用您的类型定义文件。
键入自定义命令
我们创建了一些全局自定义命令,例如cy.login()
来通过 API 处理登录,因此它可以在我们所有的规范文件中重用。 这是一个示例,说明如何在给定用户凭据的情况下键入自己的登录自定义命令并返回身份验证令牌。
键入环境变量
为了处理多个测试环境,例如 dev 和 staging,我们利用了配置环境变量的优势,例如:“testEnv”来保存我们当前正在测试的环境,例如 staging,“apiHost”来保存后端 API 主机,以及其他变量。 您可以输入Cypress.env()
调用,以更好地输入依赖于使用这些环境变量值的函数和其他对象,例如。
打字插件
我们创建了许多cy.task()
插件函数来处理 API 调用、轮询服务以及检查测试电子邮件收件箱中的匹配电子邮件。 以前,当链接任何这些函数调用(如cy.task().then((data) => {})
时,链接的数据主体将被键入为any
或unknown
,这对我们的 TypeScript 文件来说不是很好。 我们通过 Cypress 示例发现了如何根据插件名称和函数调用中传递的参数更好地键入插件。 这允许我们的 TypeScript 文件检测链接的数据类型是什么。
我们遇到的一个微妙问题是插件名称和参数必须与您输入的方式完全匹配。我们发现在编辑器中将鼠标悬停在链接的 .then( .then()
类型和cy.task()
参数对象上以加倍很重要检查类型是否正确匹配。 有时,如果您使用来自另一个赛普拉斯函数的链接主题,例如cy.getCookie(“auth_token”).its(“value”).then((token) => { })
或cy.wrap(data).then((data) => {})
,在将其作为cy.task(..., { token, data })
函数参数传递之前,您还需要键入这些链接的数据参数,否则您仍然会看到cy.task(...).then((data) => { })
数据部分类型为any
或unknown
。 最好在许多链式 Cypress 函数类型中更加明确,例如.its(“value”).then((token: string) => {})
或cy.wrap(data).then((data: DataType) => {})
在将它们作为cy.task()
参数对象的一部分传递之前,以确保类型再次正常工作。
我们创建了单独的插件 Typescript 文件,这些文件将导出函数以在我们的plugins/index.ts
中使用。 随着插件数量的增加,我们建议您按页面或功能组织这些插件功能实现,以保持您的plugins/index.ts
文件较小。 在plugins/index.ts
文件中定义所有cy.task(...)
函数时,您应该一目了然。 您最终可以通过以下方式在index.d.ts
中输入这些任务功能:
将它们放在一个类型声明文件中
我们将自定义命令、环境变量和插件的所有类型放在support
文件夹中的index.d.ts
文件中。 我们建议您将所有 Cypress 类型也放在一个主要的 TypeScript 定义文件中,以使事情井井有条。 为了绕过 Cypress 测试代码中使用的外部依赖项中缺少的类型,您还可以定义诸如“some-lib.d.ts”之类的模块文件,其中包括declare module 'some-lib'
,以解决库的 TypeScript 警告。 您甚至可以使用 TypeScript 的导入类型功能来引入在其他插件/实用程序文件中定义的类型/接口,以避免在多个文件中重复您的类型定义。 您可以在赛普拉斯命名空间中添加这些类型,并按以下方式组织它们:
键入测试夹具对象、页面对象和规范文件
当我们想为测试环境加载不同的用户和元数据时,我们之前说明了如何将诸如“testEnv”之类的环境变量与“testing”或“staging”的值结合起来,以提取“testing”或“暂存”来自整个测试夹具对象的对象。 您可以使用泛型键入这些测试夹具环境对象,以获得所有规范共享的一致结构。 对于每个测试环境,您可以使用通用类型为测试添加相同的用户凭据和元字段,以便根据需要添加任意数量的属性。 请参见下面的示例。
输入页面对象和输入相应的规范文件取决于您使用的赛普拉斯命令、插件和其他实用程序。 在大多数情况下,键入页面对象或规范文件不需要对其 JavaScript 对应项进行太多更改(假设您已经键入了插件和环境变量调用)。 有时,您定义的页面对象辅助函数可能需要输入一些参数,或者可能需要输入从cy.request()
调用返回的响应as
response.body as SomeType
。 总体而言,您的编辑器(例如 VSCode)可以自动检测cy.task()
或cy.customCommand()
调用的链接类型,而无需在规范文件中添加更多类型来补偿任何 TypeScript 警告。
这是一个页面对象的部分示例,其中包含一些帮助函数和一个使用页面对象、登录自定义命令和插件任务的规范文件。
结论
在 Cypress 测试中添加 TypeScript 有助于我们避免错误并改善我们在编写 Cypress 测试时的开发人员体验。 使用cy.task()
、 Cypress.env()
和cy.customCommand()
函数调用时,我们可以对函数参数和输出进行更好的类型检查,并利用我们的 IDE(例如 VSCode)中的代码完成。
关键是创建您自己的类型声明文件,例如index.d.ts
文件,您可以在其中根据您的自定义命令、环境变量和任务插件函数覆盖或扩展“Cypress”和“Chainable”接口使用。 在您的页面对象和规范 TypeScript 文件中,您可以利用这些赛普拉斯函数并将鼠标悬停在或遵循预期输入和输出类型的定义。
此外,请尝试将 TypeScript 与 Cypress 一起使用,因为它在最新版本中对 TypeScript 提供了开箱即用的支持。 测试它是否可以帮助您更清楚地记录功能并避免错误的 API 使用。 您的 TypeScript 测试可能仍然与您的 JavaScript Cypress 测试相似,因此您可以一次稳定地转换一些测试以比较和对比这些方法。
如果您对更多与我们从赛普拉斯测试中学到的内容相关的帖子感兴趣,请查看以下文章:
- 编写 E2E 测试时要考虑什么
- 编写柏树测试的 1,000 英尺概述
- 在 Cypress 测试中处理电子邮件流
- 配置、组织和整合赛普拉斯测试的想法
- 将 Cypress 测试与 Docker、Buildkite 和 CICD 集成