System for defining custom component testing frameworks beyond the built-in React, Vue, and Angular support. This allows you to create component testing support for any JavaScript framework or custom component system.
Creates a definition for a custom third-party component framework that can be used with Cypress component testing.
/**
* Provides automatic code completion for Component Frameworks Definitions
* @param config - Component framework definition configuration
* @returns The configuration passed in parameter (for type safety)
*/
function defineComponentFramework(
config: ThirdPartyComponentFrameworkDefinition
): ThirdPartyComponentFrameworkDefinition;
interface ThirdPartyComponentFrameworkDefinition {
/** Unique identifier for the framework */
type: string;
/** Human-readable name of the framework */
name: string;
/** List of supported bundlers (webpack, vite, etc.) */
supportedBundlers: string[];
/** Functions to detect if this framework is being used in a project */
detectors: FrameworkDetector[];
/** Function to determine required dependencies for this framework */
dependencies: (installer: DependencyInstaller) => PackageManagerType[];
}Usage Examples:
// cypress.config.js
const { defineConfig, defineComponentFramework } = require('cypress');
const solidJsFramework = defineComponentFramework({
type: 'cypress-ct-solid-js',
name: 'Solid.js',
supportedBundlers: ['vite', 'webpack'],
detectors: [
{
file: 'package.json',
matcher: /solid-js/
}
],
dependencies: (installer) => [
installer.packageJson({
dependency: 'solid-js',
minVersion: '^1.0.0'
}),
installer.packageJson({
dependency: 'vite-plugin-solid',
minVersion: '^2.0.0'
})
]
});
module.exports = defineConfig({
component: {
devServer: solidJsFramework,
specPattern: 'src/**/*.cy.{js,jsx,ts,tsx}'
}
});Define how Cypress should detect when your custom framework is being used in a project.
interface FrameworkDetector {
/** File to check for framework presence */
file: string;
/** Pattern to match in the file content */
matcher: RegExp | string;
}
// Alternative detector interface for package.json dependencies
interface PackageJsonDetector {
file: 'package.json';
matcher: RegExp;
}
// Alternative detector interface for config files
interface ConfigFileDetector {
file: string;
matcher: (content: string) => boolean;
}Framework Detection Examples:
// Detect Svelte framework
const svelteDetectors = [
{
file: 'package.json',
matcher: /svelte/
},
{
file: 'svelte.config.js',
matcher: /export.*svelte/
}
];
// Detect Lit framework
const litDetectors = [
{
file: 'package.json',
matcher: /lit|@lit/
}
];
// Detect Stencil framework
const stencilDetectors = [
{
file: 'stencil.config.ts',
matcher: /stencil/
},
{
file: 'package.json',
matcher: /@stencil\/core/
}
];Define the dependencies required for your custom framework to work with Cypress component testing.
interface DependencyInstaller {
/** Specify a package.json dependency requirement */
packageJson(requirement: PackageRequirement): PackageManagerType;
/** Specify a custom installation script */
custom(script: string): PackageManagerType;
}
interface PackageRequirement {
/** Package name */
dependency: string;
/** Minimum version required */
minVersion?: string;
/** Whether this is a dev dependency */
dev?: boolean;
}
interface PackageManagerType {
/** Package manager type */
type: 'npm' | 'yarn' | 'pnpm';
/** Installation command */
command: string;
}Dependency Examples:
// Solid.js framework dependencies
const solidDependencies = (installer) => [
installer.packageJson({
dependency: 'solid-js',
minVersion: '^1.6.0'
}),
installer.packageJson({
dependency: 'vite-plugin-solid',
minVersion: '^2.5.0',
dev: true
}),
installer.packageJson({
dependency: '@cypress/mount-utils',
minVersion: '^1.0.0',
dev: true
})
];
// Lit framework dependencies
const litDependencies = (installer) => [
installer.packageJson({
dependency: 'lit',
minVersion: '^2.0.0'
}),
installer.packageJson({
dependency: '@web/dev-server-esbuild',
minVersion: '^0.3.0',
dev: true
})
];Here's a complete example of defining a custom framework for Solid.js:
// frameworks/solid.js
const { defineComponentFramework } = require('cypress');
module.exports = defineComponentFramework({
type: 'cypress-ct-solid-js',
name: 'Solid.js',
supportedBundlers: ['vite', 'webpack'],
detectors: [
{
file: 'package.json',
matcher: /solid-js/
},
{
file: 'vite.config.js',
matcher: /solidPlugin|vite-plugin-solid/
},
{
file: 'vite.config.ts',
matcher: /solidPlugin|vite-plugin-solid/
}
],
dependencies: (installer) => [
installer.packageJson({
dependency: 'solid-js',
minVersion: '^1.6.0'
}),
installer.packageJson({
dependency: 'vite-plugin-solid',
minVersion: '^2.5.0',
dev: true
}),
installer.packageJson({
dependency: '@cypress/mount-utils',
minVersion: '^1.0.0',
dev: true
})
]
});When creating a custom framework, you'll also need to implement a mount function:
// cypress/support/solid-mount.js
import { render } from 'solid-js/web';
import { getContainerEl, setupHooks } from '@cypress/mount-utils';
let dispose;
function cleanup() {
if (dispose) {
dispose();
dispose = null;
}
}
export function mount(component, options = {}) {
return cy.then(() => {
// Clean up previous mount
cleanup();
// Get the container element
const root = getContainerEl();
// Render the Solid component
dispose = render(() => component, root);
// Log the mount operation
if (options.log !== false) {
Cypress.log({
name: 'mount',
message: 'Solid.js component'
});
}
return cy.wrap({ component }).then(() => ({ component }));
});
}
// Set up cleanup hooks
setupHooks(cleanup);Once your custom framework is defined and the mount function is implemented:
// cypress/component/SolidButton.cy.js
import { mount } from '../support/solid-mount';
import Button from './Button'; // Solid.js component
describe('Solid Button', () => {
it('renders and responds to clicks', () => {
let clicked = false;
const handleClick = () => { clicked = true; };
mount(() => <Button onClick={handleClick}>Click me</Button>);
cy.contains('Click me').should('be.visible');
cy.contains('Click me').click().then(() => {
expect(clicked).to.be.true;
});
});
});Integrate your custom framework with Cypress configuration:
// cypress.config.js
const { defineConfig } = require('cypress');
const solidFramework = require('./frameworks/solid');
module.exports = defineConfig({
component: {
devServer: {
framework: solidFramework.type,
bundler: 'vite',
viteConfig: {
plugins: [solidPlugin()]
}
},
specPattern: 'src/**/*.cy.{js,jsx,ts,tsx}',
supportFile: 'cypress/support/component.js'
}
});For more sophisticated frameworks, you can implement additional features:
// cypress/support/solid-commands.js
Cypress.Commands.add('solidComponent', { prevSubject: true }, (subject) => {
// Custom assertions for Solid.js components
return cy.wrap(subject).should('exist');
});
// Usage
cy.get('[data-cy=my-component]').solidComponent();// cypress/support/solid-utils.js
export function createSignal(initialValue) {
// Utility functions specific to your framework
return { value: initialValue };
}
export function waitForReactivity() {
// Wait for framework's reactivity system to update
return cy.wait(0); // or more sophisticated waiting logic
}Test your custom framework implementation:
// cypress/component/framework-test.cy.js
import { mount } from '../support/solid-mount';
describe('Custom Framework Integration', () => {
it('mounts components correctly', () => {
const TestComponent = () => <div data-cy="test">Framework works!</div>;
mount(TestComponent);
cy.get('[data-cy=test]').should('contain', 'Framework works!');
});
it('handles props and state', () => {
const Counter = (props) => {
const [count, setCount] = createSignal(props.initial || 0);
return (
<div>
<span data-cy="count">{count()}</span>
<button data-cy="increment" onClick={() => setCount(c => c + 1)}>
+1
</button>
</div>
);
};
mount(() => <Counter initial={5} />);
cy.get('[data-cy=count]').should('contain', '5');
cy.get('[data-cy=increment]').click();
cy.get('[data-cy=count]').should('contain', '6');
});
});This custom framework system allows you to extend Cypress component testing to any JavaScript framework, providing the same powerful testing capabilities that are available for React, Vue, and Angular components.