Skip to main content

Custom Frameworks

info
What you'll learn​
  • How to customize Cypress to support your favorite framework
  • How to create a custom Framework Definition and Mount Adapter for your framework
  • How to test and publish your custom framework

Cypress Component Testing includes official support for many popular libraries and frameworks such as React, Angular, and Vue. All officially supported libraries feature a first class onboarding experience, where we detect and scaffold the correct files, and a framework-specific mount adapter to render your components. We call this collection of features a Framework Definition since it defines the requirements for a library or framework to work in Cypress.

If your favorite library isn't featured, don't worry - we expose the same API we use internally for the Cypress community to define their own Framework Definitions.

In this guide, you'll learn how to author a Framework Definition, which will enjoy the same polished onboarding experience as our officially supported frameworks.

Concepts​

There are a few requirements for authoring a Framework Definition.

The Definition is required when users configure Component Testing for the first time. The Mount adapter is used to render components when writing tests.

To simplify this process, we recommend starting development using our official template.

Framework Definition​

Below is a minimal Framework Definition. Note that defineFrameworkDefinition is purely for type safety, similar to defineConfig in cypress.config.

There is one important convention; the type key in defineFrameworkDefinition should match the name of your package on npm, and should be named using one of the following conventions:

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

Some examples of valid names include:

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

When configuring a project to use Component Testing, Cypress will load any dependencies following this naming convention from the project's node_modules and present them as framework options.

A simple example of a Framework Definition for the Solid.js library is shown below. We generally recommend naming this definition.cjs. In our official template, this file is at the root level of the package.

const { defineFrameworkDefinition } = require('cypress')

const solidDep = {
// Unique, semantic identifier.
type: 'solid-js',

// Human readable name.
name: 'Solid',

// Package name install from `npm`.
package: 'solid-js',

/**
* Similar to package, but can include a version or tag.
* Used during setup to generate an install command for users.
* Eg: `solid-js@next`
*/
installer: 'solid-js',

// Human readable description.
description:
'A declarative, efficient, and flexible JavaScript library for building user interfaces.',

// Minimum supported version.
minVersion: '^1.6.0',
}

/**
* Similar to above. Create an smooth, seamless setup experience
* by ensuring the user has all the necessary dependencies.
* @type {Cypress.CypressComponentDependency}
*/
const solidVitePlugin = {
type: 'solid-js-vite-plugin',
name: 'Vite Plugin Solid',
package: 'vite-plugin-solid',
installer: 'vite-plugin-solid',
description: 'A simple integration to run solid-js with vite',
minVersion: '^1.6.0 || ^2.0.0',
}

/**
* The actual definition.
*/
module.exports = defineFrameworkDefinition({
/**
* This should match the `npm` package name.
* The convention required to ensure your Definition is processed
* by Cypress is `cypress-ct-*` for global packages, or
* `@org/cypress-ct-*` for organization level packages.
*/
type: '@lmiller1990/cypress-ct-solid-js',

/**
* The label that shows up when configuring Component Testing
* for the first time.
*/
name: 'Solid.js',

/**
* Supported bundlers. Can be "webpack" and/or "vite".
* In this example we only support Solid.js with Vite.
*/
supportedBundlers: ['vite'],

/**
* Used by Cypress to automatically detect the correct Framework Definition
* based on the user's project.
* In this example, if a module matching `solidDep`
* is found in the user's project,
* Solid.js will automatically be selected when configuring Component Testing.
*/
detectors: [solidDep],

/**
* Supply a set of dependencies a project should have to use this Framework Definition. The user will be prompted to install them if they are not found.
* Optionally, supply different dependencies based on the chosen bundler.
*/
dependencies: (bundler) => {
return [solidDep, solidVitePlugin]
},

/**
* An SVG icon. Shown when configuring Component Testing for the first time.
* Optional, but good for branding your Framework Definition.
*/
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>
`,
})

Our Framework Definition shows up in Cypress! It has the "community" label, indicating it's a third party definition.

custom framework definition

We defined the dependencies, which are also correctly handled - we haven't installed them all, so Cypress is prompting us to do so:

required dependencies

Mount Adapter​

The second part of defining a Framework Definition is the Mount Adapter. This is the function that renders the component in your tests using cy.mount().

By default, Cypress will look for this as a mount function that is a named export from the package. This should be written in a index.mjs file. This example is for a Solid.js mount adapter:

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

let dispose

function cleanup() {
dispose?.()
}

/**
* @param {() => JSX.Element} - component to render
*/
export function mount(component, options = {}) {
// Retrieve root DOM element that Cypress has prepared for this test
const root = getContainerEl()

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

// Wait until next microtick to ensure any async render logic has executed
return cy.wait(0, { log: false }).then(() => {
if (options.log !== false) {
Cypress.log({
name: 'mount',
message: 'Mounted component',
})
}
})
}

// Cleanup between each test
setupHooks(cleanup)

This is different for each library, but the concept is the same - identify how to mount or render a component in your library, and implement it in a function named mount in index.mjs.

When a user configures Component Testing with your Framework Definition we automatically configure a cy.mount command using your mount function in the Component Testing supportFile:

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

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

package.json​

The final thing you need is a correctly configured package.json. This example was created using our official template.

There are two fields of note:

  • name: Your package name which must follow the cypress-ct-*/@org/cypress-ct-* convention
  • exports: Object referencing the two files we created to comprise the Framework Definition. The node entry points to the Definition file, and the default entry points to the Mount Adapter:
{
"name": "@lmiller1990/cypress-ct-solid-js",
"version": "0.0.4",
"description": "Example Framework Definition for Cypress and 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"
}
}

Testing​

If you develop the Framework Definition file using TypeScript, for example by using our official template, as long as you don't have any compile time errors, everything should work as expected. If you do run into unexpected behavior, please file an issue.

Mount Adapters can be more complex to test. In general, we recommend testing them in the same way users consume them - using Cypress Component Testing. A minimal test suite for a simple Solid.js Mount Adapter can be found here. Alternatively, take a look at our official React and Angular Mount Adapters, both of which have extensive test suites.

Publishing on npm​

That's it! Publish your Framework Definition on npm and start using it.

Available Framework Definitions​

You can find a list of available Framework Definitions here.

If you have created a Framework Definition we would be delighted to mention it in our documentation so other Cypress users on the same framework can find it. Please submit a Pull Request!