Skip to main content
Cypress应用

自定义框架

info
您将学习到
  • 如何定制Cypress以支持您喜爱的框架
  • 如何为您的框架创建自定义框架定义和挂载适配器
  • 如何测试和发布您的自定义框架

Cypress组件测试包含对许多流行库和框架的官方支持,例如ReactAngularVue。所有官方支持的库都提供一流的入门体验,我们会检测并搭建正确的文件,以及一个框架特定的mount适配器来渲染您的组件。我们将这组功能称为_框架定义_,因为它定义了库或框架在Cypress中工作的要求。

如果您喜爱的库不在其中,别担心——我们向Cypress社区公开了与我们内部使用的相同API,以便定义他们自己的框架定义。

在本指南中,您将学习如何编写框架定义,它将享有与我们官方支持框架相同的精致入门体验。

概念

编写框架定义有几个要求。

在用户首次配置组件测试时,定义文件是必需的。挂载适配器用于在编写测试时渲染组件。

为了简化此过程,我们建议使用我们的官方模板开始开发。

框架定义

以下是一个最小的框架定义。注意defineFrameworkDefinition仅用于类型安全,类似于cypress.config中的defineConfig

有一个重要的约定:defineFrameworkDefinition中的type键应与npm上的包名匹配,并且应使用以下约定之一命名:

  • cypress-ct-*
  • @organization/cypress-ct-*

一些有效名称的示例包括:

  • cypress-ct-react-js
  • cypress-ct-svelte-testing
  • @cypress/cypress-ct-react
  • @angular/cypress-ct-angular

在配置项目以使用组件测试时,Cypress将从项目的node_modules中加载遵循此命名约定的任何依赖项,并将它们作为框架选项呈现。

下面是一个为Solid.js库编写的框架定义的简单示例。我们通常建议将此文件命名为definition.cjs。在我们的官方模板中,此文件位于包的根级别。

const { defineFrameworkDefinition } = require('cypress')

const solidDep = {
// 唯一、语义化的标识符。
type: 'solid-js',

// 人类可读的名称。
name: 'Solid',

// 从`npm`安装的包名。
package: 'solid-js',

/**
* 类似于package,但可以包含版本或标签。
* 在设置期间用于为用户生成安装命令。
* 例如:`solid-js@next`
*/
installer: 'solid-js',

// 人类可读的描述。
description:
'一个声明式、高效且灵活的JavaScript库,用于构建用户界面。',

// 最低支持的版本。
minVersion: '^1.6.0',
}

/**
* 类似于上面。通过确保用户拥有所有必要的依赖项,
* 创建流畅、无缝的设置体验。
* @type {Cypress.CypressComponentDependency}
*/
const solidVitePlugin = {
type: 'solid-js-vite-plugin',
name: 'Vite Plugin Solid',
package: 'vite-plugin-solid',
installer: 'vite-plugin-solid',
description: '一个简单的集成,用于在vite中运行solid-js',
minVersion: '^1.6.0 || ^2.0.0',
}

/**
* 实际的定义。
*/
module.exports = defineFrameworkDefinition({
/**
* 这应与`npm`包名匹配。
* 确保您的定义被Cypress处理的命名约定是
* `cypress-ct-*`用于全局包,或
* `@org/cypress-ct-*`用于组织级别的包。
*/
type: '@lmiller1990/cypress-ct-solid-js',

/**
* 在首次配置组件测试时显示的标签。
*/
name: 'Solid.js',

/**
* 支持的打包工具。可以是"webpack"和/或"vite"。
* 在此示例中,我们仅支持Solid.js与Vite。
*/
supportedBundlers: ['vite'],

/**
* Cypress用于根据用户的项目自动检测正确的框架定义。
* 在此示例中,如果在用户的项目中找到与`solidDep`匹配的模块,
* 则在配置组件测试时将自动选择Solid.js。
*/
detectors: [solidDep],

/**
* 提供项目应具有的一组依赖项以使用此框架定义。如果未找到,将提示用户安装它们。
* 可选地,根据所选的打包工具提供不同的依赖项。
*/
dependencies: (bundler) => {
return [solidDep, solidVitePlugin]
},

/**
* SVG图标。在首次配置组件测试时显示。
* 可选,但对于品牌化您的框架定义很有用。
*/
icon: `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 166 155.3"><path d="M163 35S110-4 69 5l-3 1c-6 2-11 5-14 9l-2 3-15 26 26 5c11 7 25 10 38 7l46 9 18-30z" fill="#76b3e1"/><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="27.5" y1="3" x2="152" y2="63.5"><stop offset=".1" stop-color="#76b3e1"/><stop offset=".3" stop-color="#dcf2fd"/><stop offset="1" stop-color="#76b3e1"/></linearGradient><path d="M163 35S110-4 69 5l-3 1c-6 2-11 5-14 9l-2 3-15 26 26 5c11 7 25 10 38 7l46 9 18-30z" opacity=".3" fill="url(#a)"/><path d="M52 35l-4 1c-17 5-22 21-13 35 10 13 31 20 48 15l62-21S92 26 52 35z" fill="#518ac8"/><linearGradient id="b" gradientUnits="userSpaceOnUse" x1="95.8" y1="32.6" x2="74" y2="105.2"><stop offset="0" stop-color="#76b3e1"/><stop offset=".5" stop-color="#4377bb"/><stop offset="1" stop-color="#1f3b77"/></linearGradient><path d="M52 35l-4 1c-17 5-22 21npm install https://cdn.cypress.io/beta/npm/12.6.0/darwin-arm64/feature/ct-public-api-ab820f062d313fbef51665bdd1d883c69d89b3be/cypress.tgz-13 35 10 13 31 20 48 15l62-21S92 26 52 35z" opacity=".3" fill="url(#b)"/><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="18.4" y1="64.2" x2="144.3" y2="149.8"><stop offset="0" stop-color="#315aa9"/><stop offset=".5" stop-color="#518ac8"/><stop offset="1" stop-color="#315aa9"/></linearGradient><path d="M134 80a45 45 0 00-48-15L24 85 4 120l112 19 20-36c4-7 3-15-2-23z" fill="url(#c)"/><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="75.2" y1="74.5" x2="24.4" y2="260.8"><stop offset="0" stop-color="#4377bb"/><stop offset=".5" stop-color="#1a336b"/><stop offset="1" stop-color="#1a336b"/></linearGradient><path d="M114 115a45 45 0 00-48-15L4 120s53 40 94 30l3-1c17-5 23-21 13-34z" fill="url(#d)"/></svg>
`,
})

我们的框架定义出现在Cypress中!它有“community”标签,表明这是一个第三方定义。

自定义框架定义

我们定义了dependencies,它们也得到了正确处理——我们还没有全部安装它们,所以Cypress提示我们这样做:

必需的依赖项

挂载适配器

定义框架定义的第二部分是挂载适配器。这是在测试中使用cy.mount()渲染组件的函数。

默认情况下,Cypress会将其作为包的命名导出中的mount函数查找。这应写在index.mjs文件中。此示例是为Solid.js编写的挂载适配器:

import { getContainerEl, setupHooks } from '@cypress/mount-utils'
import { render } from 'solid-js/web'

let dispose

function cleanup() {
dispose?.()
}

/**
* @param {() => JSX.Element} - 要渲染的组件
*/
export function mount(component, options = {}) {
// 检索Cypress为此测试准备的根DOM元素
const root = getContainerEl()

dispose = render(() => component, root)

// 等待下一个微任务以确保任何异步渲染逻辑已执行
return cy.wait(0, { log: false }).then(() => {
if (options.log !== false) {
Cypress.log({
name: 'mount',
message: '已挂载组件',
})
}
})
}

// 在每个测试之间清理
setupHooks(cleanup)

这对于每个库都是不同的,但概念是相同的——确定如何在您的库中挂载或渲染组件,并在index.mjs中实现一个名为mount的函数。

当用户使用您的框架定义配置组件测试时,我们会在组件测试的supportFile中自动配置一个使用您的mount函数的cy.mount命令:

import { mount } from '@lmiller1990/cypress-ct-solid-js'

Cypress.Commands.add('mount', mount)

package.json

最后,您需要一个正确配置的package.json。此示例是使用我们的官方模板创建的。

有两个需要注意的字段:

  • name: 您的包名,必须遵循cypress-ct-*/@org/cypress-ct-*约定
  • exports: 对象引用我们创建的两个文件以组成框架定义。node条目指向定义文件,default条目指向挂载适配器:
{
"name": "@lmiller1990/cypress-ct-solid-js",
"version": "0.0.4",
"description": "Cypress和Solid.js的示例框架定义",
"exports": {
"node": "./definition.cjs",
"default": "./index.mjs"
},
"files": [
"package.json",
"definition.cjs",
"index.mjs"
],
"dependencies": {
"@cypress/mount-utils": "^4.0.0"
},
"devDependencies": {
"solid-js": "^1.6.0"
},
"peerDependencies": {
"solid-js": "^1.6.0"
"cypress": "^12.7.0"
}
}

测试

如果您使用TypeScript开发框架定义文件,例如使用我们的官方模板,只要您没有任何编译时错误,一切都应按预期工作。如果您遇到意外行为,请提交问题

挂载适配器的测试可能更复杂。一般来说,我们建议以用户使用它们的方式测试它们——使用Cypress组件测试。一个简单的Solid.js挂载适配器的最小测试套件可以在这里找到。或者,看看我们官方的ReactAngular挂载适配器,它们都有广泛的测试套件。

在npm上发布

就是这样!在npm上发布您的框架定义并开始使用它。

可用的框架定义

您可以在此处找到可用框架定义的列表/app/component-testing/get-started#Supported-Frameworks

如果您创建了一个框架定义,我们很乐意在我们的文档中提到它,以便同一框架上的其他Cypress用户可以找到它。请提交拉取请求