Skip to main content
Cypress应用

TypeScript支持

info
你将学到
  • 如何在Cypress中设置TypeScript
  • 如何为自定义命令、断言和插件配置TypeScript
  • 如何在Cypress组件测试中使用TypeScript
  • 如何避免与Jest的类型冲突
  • 如何为TypeScript设置开发环境

Cypress内置了 官方类型声明 支持TypeScript。这允许你使用TypeScript编写测试。

开始使用

安装TypeScript

要在Cypress中使用TypeScript,你需要TypeScript 4.0+。如果你的框架尚未安装TypeScript,你需要先安装:

npm install typescript --save-dev

配置tsconfig.json

我们建议在 cypress文件夹 内创建一个 tsconfig.json 并配置如下:

tsconfig.json
{
"compilerOptions": {
"target": "es5",
"lib": ["es5", "dom"],
"sourceMap": true,
"types": ["cypress", "node"]
},
"include": ["**/*.ts"]
}

"types"会告诉TypeScript编译器仅包含Cypress的类型定义。这将解决项目中同时使用@types/chai@types/jquery的情况。由于 ChaijQuery是命名空间(全局变量),不兼容的版本会导致包管理器(yarnnpm)嵌套并包含多个定义,从而引发冲突。

caution

如果上述设置未生效,你可能需要重启IDE的TypeScript服务器。例如:

VS Code(在.ts或.js文件中):

  • 打开命令面板(Mac:cmd+shift+p,Windows:ctrl+shift+p
  • 输入"restart ts"并选择"TypeScript: Restart TS server."选项

如果仍不生效,尝试重启IDE。

处理Cypress配置和插件

Cypress需要能够转译用TypeScript编写的Cypress配置和插件,以便在Cypress的Node.js运行时中执行。为此,Cypress会尝试读取用户的TypeScript和项目配置,以将正确的TypeScript加载器应用到Cypress的Node.js运行时。

如果你的项目是一个ESM包(即ECMAScript模块的缩写),Cypress会尝试应用ts-node/esm Node.js加载器来解析Cypress配置和插件。如果项目的package.json中包含type: "module"键值对,Cypress会认为该项目是ESM

否则,Cypress会在其Node.js运行时中引入常规的ts-node。 由于Node.js本身只能解释CommonJS文件,Cypress会尝试使你的TypeScript配置与Cypress的Node.js运行时兼容。 为此,Cypress会覆盖项目tsconfig.json中的以下配置值:

{
"module": "commonjs",
"moduleResolution": "node",
"preserveValueImports": false
}

这不会影响你的项目或其TypeScript配置设置。此覆盖仅在Cypress运行时的上下文中生效。

扩展TypeScript支持

自定义命令的类型

当向cy对象添加自定义命令时,你可以手动添加它们的类型以避免TypeScript错误。

例如,如果你在 supportFile中添加了cy.dataCy命令:

// cypress/support/index.ts
Cypress.Commands.add('dataCy', (value) => {
return cy.get(`[data-cy=${value}]`)
})

然后你可以将dataCy命令添加到全局的Cypress Chainable接口(之所以称为Chainable,是因为命令可以链式调用)。

// cypress/support/index.ts
declare global {
namespace Cypress {
interface Chainable {
/**
* 通过data-cy属性选择DOM元素的自定义命令。
* @example cy.dataCy('greeting')
*/
dataCy(value: string): Chainable<JQuery<HTMLElement>>
}
}
}
info

在方法类型上方添加详细的JSDoc注释会让使用你的自定义命令的用户感到非常贴心。

info

实现回调的所有参数类型会根据声明的接口自动推断。因此,在上面的例子中,value会隐式地具有string类型。

在你的测试文件中,现在可以按预期使用自定义命令

it('works', () => {
// from your cypress/e2e/spec.cy.ts
cy.visit('/')
// IntelliSense和TS编译器应该
// 不会对未知方法报错
cy.dataCy('greeting')
})

添加子命令或双命令

当你使用prevSubject添加自定义命令时,Cypress会根据指定的prevSubject自动推断主题类型。

// cypress/support/index.ts
declare global {
namespace Cypress {
interface Chainable {
/**
* 向输入元素输入几个随机单词的自定义命令
* @param count=3
* @example cy.get('input').typeRandomWords()
*/
typeRandomWords(
count?: number,
options?: Partial<TypeOptions>
): Chainable<JQuery<HTMLElement>>
}
}
}
// cypress/support/index.ts
Cypress.Commands.add(
'typeRandomWords',
{ prevSubject: 'element' },
(subject /* :JQuery<HTMLElement> */, count = 3, options?) => {
return cy.wrap(subject).type(generateRandomWords(count), options)
}
)

覆盖子命令或双命令

当覆盖使用prevSubject的内置或自定义命令时,你必须指定泛型参数以帮助类型检查器理解prevSubject的类型。

interface TypeOptions extends Cypress.TypeOptions {
sensitive: boolean
}

Cypress.Commands.overwrite<'type', 'element'>(
'type',
(originalFn, element, text, options?: Partial<TypeOptions>) => {
if (options && options.sensitive) {
// 关闭原始日志
options.log = false
// 创建我们自己的带掩码消息的日志
Cypress.log({
$el: element,
name: 'type',
message: '*'.repeat(text.length),
})
}

return originalFn(element, text, options)
}
)

如你所见,这里使用了泛型参数<'type', 'element'>

  1. 第一个参数是命令名称,与传递给Cypress.Commands.overwrite的第一个参数相同。
  2. 第二个参数是原始命令使用的prevSubject类型。可能的值:
    • 'element'推断为JQuery<HTMLElement>
    • 'window'推断为Window
    • 'document'推断为Document
    • 'optional'推断为unknown

示例:

自定义断言的类型

如果你扩展了Cypress断言,你可以扩展断言类型以使TypeScript编译器理解新方法。参见 配方:添加Chai断言 获取说明。

插件的类型

你可以通过以下方式在 插件文件中使用Cypress的类型声明:

// cypress/plugins/index.ts

/**
* @type {Cypress.PluginConfig}
*/
module.exports = (on, config) => {}

使用外部类型文件

你可能会发现将类型从支持文件移动到外部 声明(*.d.ts)文件 更容易组织。为此,创建一个新文件,如_cypress.d.ts_,并将自定义命令/断言的类型从支持文件剪切到新文件中。以下是将组件测试应用默认附带的cy.mount自定义类型移动到根级别_cypress.d.ts_文件的示例。

import { mount } from 'cypress/react'

// 扩展Cypress命名空间以包含
// 自定义命令的类型定义。
// 或者,可以在cypress/support/component.d.ts中定义
// 并在测试文件顶部添加<reference path="./component" />。
declare global {
namespace Cypress {
interface Chainable {
mount: typeof mount
}
}
}

你可能需要在项目的任何_tsconfig.json_文件中的include选项中包含_*.d.ts_,以便TypeScript能够识别新类型:

"include": [
"src",
"./cypress.d.ts"
]
"include": [
"**/*.ts",
"../cypress.d.ts"
]

设置开发环境

请参考你的代码编辑器在 TypeScript的编辑器支持文档 中的说明,并按照IDE的指南在继续之前配置TypeScript支持和 智能代码补全。 TypeScript支持内置在Visual Studio CodeVisual StudioWebStorm中——所有其他编辑器都需要额外设置。

与Jest的类型冲突

如果你在同一个项目中同时使用Jest和Cypress,两个测试运行器注册的全局TypeScript类型可能会冲突。例如,Jest和Cypress都为describeit函数提供了冲突的类型。Jest和Cypress内置的Expect都为expect断言提供了冲突的类型等。

你可以考虑为应用配置单独的tsconfig.json来解决 与Jest的类型冲突。 你需要在根tsconfig.json文件中排除cypress.config.tscypressnode_modules

tsconfig.json
{
"exclude": ["cypress.config.ts", "cypress", "node_modules"]
}

历史

版本变更
13.0.0将最低要求的TypeScript版本从3.4+提高到4.0+
10.0.0更新指南以涵盖组件测试的TypeScript设置
5.0.0将最低要求的TypeScript版本从2.9+提高到3.4+
4.4.0添加了对TypeScript的支持,无需通过预处理器进行自己的转译。

另请参阅