Unofficial Enzyme adapter specifically designed for React 17 applications, enabling developers to use Enzyme's testing utilities with React 17's updated architecture.
npx @tessl/cli install tessl/npm-wojtekmaj--enzyme-adapter-react-17@0.8.0An unofficial Enzyme adapter specifically designed for React 17 applications, enabling developers to use Enzyme's testing utilities with React 17's updated architecture. This adapter acts as a bridge between Enzyme's testing framework and React 17's fiber reconciler, supporting shallow rendering, full DOM rendering, and static rendering of React components.
npm install --save-dev @wojtekmaj/enzyme-adapter-react-17import Adapter from '@wojtekmaj/enzyme-adapter-react-17';CommonJS:
const Adapter = require('@wojtekmaj/enzyme-adapter-react-17');TypeScript:
import * as Adapter from '@wojtekmaj/enzyme-adapter-react-17';
// or
import Adapter = require('@wojtekmaj/enzyme-adapter-react-17');import Enzyme from 'enzyme';
import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
// Configure Enzyme to use the React 17 adapter
Enzyme.configure({ adapter: new Adapter() });
// Now use Enzyme's standard API
import { shallow, mount, render } from 'enzyme';
import MyComponent from './MyComponent';
// Shallow rendering
const wrapper = shallow(<MyComponent prop="value" />);
// Full DOM rendering
const wrapper = mount(<MyComponent prop="value" />);
// Static rendering
const wrapper = render(<MyComponent prop="value" />);The adapter extends Enzyme's EnzymeAdapter class and provides React 17-specific implementations for:
The main adapter class that extends EnzymeAdapter and provides React 17 compatibility.
/**
* React 17 Enzyme Adapter class
* Extends EnzymeAdapter to provide React 17 compatibility
*/
class ReactSeventeenAdapter extends EnzymeAdapter {
constructor();
// Renderer factory methods
createMountRenderer(options: MountRendererOptions): MountRenderer;
createShallowRenderer(options: ShallowRendererOptions): ShallowRenderer;
createStringRenderer(options: StringRendererOptions): StringRenderer;
createRenderer(options: RendererOptions): Renderer;
// Element and node manipulation
wrap(element: ReactElement): ReactWrapper;
nodeToElement(node: EnzymeNode): ReactElement | null;
elementToNode(element: ReactElement): EnzymeNode;
nodeToHostNode(node: EnzymeNode, supportsArray?: boolean): Node | Node[];
// Type checking and validation
matchesElementType(node: EnzymeNode, matchingType: ComponentType): boolean;
isValidElement(element: any): boolean;
isValidElementType(object: any): boolean;
isFragment(fragment: any): boolean;
isCustomComponent(type: ComponentType): boolean;
isContextConsumer(type: ComponentType): boolean;
isCustomComponentElement(inst: any): boolean;
// Utility methods
displayNameOfNode(node: EnzymeNode): string | null;
getProviderFromConsumer(Consumer: ComponentType): ComponentType | null;
createElement(...args: any[]): ReactElement;
wrapWithWrappingComponent(node: EnzymeNode, options: WrappingComponentOptions): EnzymeNode;
}Full DOM rendering capabilities for integration and end-to-end testing.
interface MountRenderer {
/**
* Renders a React element to the DOM
* @param el - React element to render
* @param context - Optional context for the element
* @param callback - Optional callback after rendering
*/
render(el: ReactElement, context?: any, callback?: () => void): void;
/**
* Unmounts the rendered component from the DOM
*/
unmount(): void;
/**
* Gets the rendered component tree as EnzymeNode
* @returns The root node of the rendered tree
*/
getNode(): EnzymeNode;
/**
* Simulates an error in the component tree
* @param nodeHierarchy - Array of nodes representing the error hierarchy
* @param rootNode - Root node of the component tree
* @param error - Error object to simulate
*/
simulateError(nodeHierarchy: EnzymeNode[], rootNode: EnzymeNode, error: Error): void;
/**
* Simulates a DOM event on a component node
* @param node - Target node for the event
* @param event - Event name (e.g., 'click', 'change')
* @param mock - Mock event object
*/
simulateEvent(node: EnzymeNode, event: string, mock: any): void;
/**
* Batches React updates for optimal performance
* @param fn - Function containing React updates
*/
batchedUpdates(fn: () => void): void;
/**
* Gets renderer for wrapping components
* @returns Renderer for wrapping components
*/
getWrappingComponentRenderer(): any;
}
interface MountRendererOptions {
mode?: 'mount';
attachTo?: Element;
hydrateIn?: Element;
wrappingComponentProps?: any;
// Note: suspenseFallback is NOT supported by mount renderer
[key: string]: any;
}Shallow rendering for unit testing individual components in isolation.
interface ShallowRenderer {
/**
* Renders a React element shallowly (one level deep)
* @param el - React element to render
* @param unmaskedContext - Context object for the element
* @param options - Additional rendering options
*/
render(el: ReactElement, unmaskedContext?: any, options?: ShallowRenderOptions): void;
/**
* Unmounts the shallow rendered component
*/
unmount(): void;
/**
* Gets the shallow rendered component tree
* @returns The root node of the shallow rendered tree
*/
getNode(): EnzymeNode;
/**
* Simulates an error in the shallow component tree
* @param nodeHierarchy - Array of nodes representing the error hierarchy
* @param rootNode - Root node of the component tree
* @param error - Error object to simulate
*/
simulateError(nodeHierarchy: EnzymeNode[], rootNode: EnzymeNode, error: Error): void;
/**
* Simulates events on shallow rendered components
* @param node - Target node for the event
* @param event - Event name
* @param args - Event arguments
*/
simulateEvent(node: EnzymeNode, event: string, ...args: any[]): void;
/**
* Batches updates for shallow rendering
* @param fn - Function containing updates
*/
batchedUpdates(fn: () => void): void;
/**
* Validates component prop types
* @param typeSpecs - PropTypes specification object
* @param values - Actual prop values
* @param location - Location string for error reporting
* @param hierarchy - Component hierarchy for stack traces
*/
checkPropTypes(typeSpecs: any, values: any, location: string, hierarchy: EnzymeNode[]): void;
}
interface ShallowRendererOptions {
mode?: 'shallow';
suspenseFallback?: boolean; // Must be boolean or undefined
[key: string]: any;
}
interface ShallowRenderOptions {
providerValues?: Map<any, any>;
[key: string]: any;
}Server-side rendering capabilities for static HTML generation.
interface StringRenderer {
/**
* Renders a React element to a static HTML string
* @param el - React element to render
* @param context - Optional context for server-side rendering
* @returns HTML string representation
*/
render(el: ReactElement, context?: any): string;
}
interface StringRendererOptions {
mode?: 'string';
// Note: suspenseFallback is NOT supported by string renderer
[key: string]: any;
}Options that can be passed to the adapter and its renderers.
interface RendererOptions {
/**
* Rendering mode: 'mount', 'shallow', or 'string'
*/
mode: 'mount' | 'shallow' | 'string';
/**
* Whether to use fallback content for Suspense components
* @default false
*/
suspenseFallback?: boolean;
/**
* Additional context for rendering
*/
context?: any;
/**
* Provider values for context testing
*/
providerValues?: Map<any, any>;
/**
* Additional options specific to each renderer
*/
[key: string]: any;
}
interface WrappingComponentOptions {
/**
* Wrapping component for enhanced testing scenarios
*/
wrappingComponent?: ComponentType;
/**
* Props to pass to the wrapping component
*/
wrappingComponentProps?: any;
[key: string]: any;
}Core types used throughout the adapter API.
/**
* React element type (imported from React)
*/
type ReactElement = import('react').ReactElement;
/**
* React component type
*/
type ComponentType = import('react').ComponentType;
/**
* Enzyme's internal node representation
*/
interface EnzymeNode {
nodeType: string;
type: ComponentType | string;
props: any;
key: string | null;
ref: any;
instance: any;
rendered: EnzymeNode | EnzymeNode[] | null;
}
/**
* React wrapper for mount rendering
*/
interface ReactWrapper {
find(selector: string): ReactWrapper;
props(): any;
state(): any;
simulate(event: string, ...args: any[]): ReactWrapper;
setProps(props: any): ReactWrapper;
setState(state: any): ReactWrapper;
unmount(): ReactWrapper;
update(): ReactWrapper;
[key: string]: any;
}The adapter handles various error scenarios gracefully:
// Error boundary testing
const wrapper = mount(
<ErrorBoundary>
<ComponentThatThrows />
</ErrorBoundary>
);
// Simulate errors for testing error boundaries
wrapper.find('ComponentThatThrows').simulateError(new Error('Test error'));import { mount } from 'enzyme';
import { useState } from 'react';
function HookComponent() {
const [count, setCount] = useState(0);
return (
<div>
<span>{count}</span>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
const wrapper = mount(<HookComponent />);
expect(wrapper.find('span').text()).toBe('0');
wrapper.find('button').simulate('click');
expect(wrapper.find('span').text()).toBe('1');import { mount } from 'enzyme';
import { createContext, useContext } from 'react';
const ThemeContext = createContext('light');
function ThemedComponent() {
const theme = useContext(ThemeContext);
return <div className={theme}>Themed content</div>;
}
const wrapper = mount(
<ThemeContext.Provider value="dark">
<ThemedComponent />
</ThemeContext.Provider>
);
expect(wrapper.find('div').hasClass('dark')).toBe(true);import { mount } from 'enzyme';
import { Suspense } from 'react';
const LazyComponent = React.lazy(() => import('./LazyComponent'));
const wrapper = mount(
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>,
{ suspenseFallback: true }
);
// Test fallback content
expect(wrapper.find('div').text()).toBe('Loading...');The adapter requires these peer dependencies to be installed:
enzyme: ^3.0.0 - The main Enzyme testing libraryreact: ^17.0.0-0 - React 17.xreact-dom: ^17.0.0-0 - React DOM 17.xInstallation example:
npm install --save-dev enzyme @wojtekmaj/enzyme-adapter-react-17 react@^17 react-dom@^17