Suite of utilities for testing Inferno applications with comprehensive tree traversal, element finding, and Jest snapshot integration.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Native Jest snapshot testing support with functions to convert VNodes and rendered components to Jest-compatible snapshots. These utilities enable seamless integration with Jest's snapshot testing capabilities for Inferno applications.
/**
* Converts a VNode to a Jest-compatible snapshot object
* @param vNode - VNode to convert to snapshot
* @returns InfernoSnapshot object compatible with Jest snapshots
*/
function vNodeToSnapshot(vNode: VNode): InfernoSnapshotThis function converts individual VNodes into the snapshot format that Jest expects, making them suitable for snapshot testing.
import { vNodeToSnapshot } from 'inferno-test-utils';
import { createElement } from 'inferno-create-element';
// Simple DOM element snapshot
const simpleVNode = <div className="test">Hello World</div>;
const snapshot = vNodeToSnapshot(simpleVNode);
console.log(snapshot);
// {
// type: "div",
// props: { className: "test" },
// children: ["Hello World"],
// $$typeof: Symbol(react.test.json)
// }
// Complex nested structure
const complexVNode = (
<div className="container">
<h1>Title</h1>
<p>Description</p>
<button disabled>Action</button>
</div>
);
const complexSnapshot = vNodeToSnapshot(complexVNode);
console.log(complexSnapshot);
// {
// type: "div",
// props: { className: "container" },
// children: [
// { type: "h1", props: {}, children: ["Title"] },
// { type: "p", props: {}, children: ["Description"] },
// { type: "button", props: { disabled: true }, children: ["Action"] }
// ],
// $$typeof: Symbol(react.test.json)
// }/**
* Renders a VNode and converts it to a Jest-compatible snapshot
* @param input - VNode to render and convert to snapshot
* @returns InfernoSnapshot object suitable for Jest snapshot testing
*/
function renderToSnapshot(input: VNode): InfernoSnapshotThis function combines rendering and snapshot conversion in one step, handling the full render lifecycle including state updates and component lifecycle methods.
import { renderToSnapshot } from 'inferno-test-utils';
import { Component } from 'inferno';
// Simple component snapshot
function SimpleComponent({ name }) {
return <div className="greeting">Hello {name}!</div>;
}
const simpleSnapshot = renderToSnapshot(<SimpleComponent name="World" />);
console.log(simpleSnapshot);
// {
// type: "div",
// props: { className: "greeting" },
// children: ["Hello World!"],
// $$typeof: Symbol(react.test.json)
// }
// Class component with state
class StatefulComponent extends Component {
constructor(props) {
super(props);
this.state = { count: props.initialCount || 0 };
}
render() {
return (
<div className="counter">
<span>Count: {this.state.count}</span>
<button>Increment</button>
</div>
);
}
}
const statefulSnapshot = renderToSnapshot(<StatefulComponent initialCount={5} />);
console.log(statefulSnapshot);
// {
// type: "div",
// props: { className: "counter" },
// children: [
// { type: "span", props: {}, children: ["Count: 5"] },
// { type: "button", props: {}, children: ["Increment"] }
// ],
// $$typeof: Symbol(react.test.json)
// }import { renderToSnapshot } from 'inferno-test-utils';
import { Component } from 'inferno';
// Component to test
class WelcomeMessage extends Component {
render() {
const { name, role } = this.props;
return (
<div className="welcome">
<h2>Welcome, {name}!</h2>
{role && <p className="role">Role: {role}</p>}
<button className="btn-primary">Get Started</button>
</div>
);
}
}
// Jest test
describe('WelcomeMessage', () => {
it('renders correctly with name only', () => {
const snapshot = renderToSnapshot(<WelcomeMessage name="John" />);
expect(snapshot).toMatchSnapshot();
});
it('renders correctly with name and role', () => {
const snapshot = renderToSnapshot(<WelcomeMessage name="Jane" role="Admin" />);
expect(snapshot).toMatchSnapshot();
});
});import { renderToSnapshot, renderIntoContainer } from 'inferno-test-utils';
import { Component } from 'inferno';
class ToggleComponent extends Component {
constructor(props) {
super(props);
this.state = { isOpen: false };
}
toggle = () => {
this.setState({ isOpen: !this.state.isOpen });
}
render() {
return (
<div className="toggle">
<button onClick={this.toggle}>
{this.state.isOpen ? 'Close' : 'Open'}
</button>
{this.state.isOpen && (
<div className="content">
<p>Toggle content is visible</p>
</div>
)}
</div>
);
}
}
describe('ToggleComponent', () => {
it('renders correctly in closed state', () => {
const snapshot = renderToSnapshot(<ToggleComponent />);
expect(snapshot).toMatchSnapshot();
});
it('renders correctly in open state', () => {
// Render component to access instance
const rendered = renderIntoContainer(<ToggleComponent />);
// Change state
rendered.toggle();
// Create snapshot of updated state
const snapshot = vNodeToSnapshot(rendered.$LI); // Access VNode from instance
expect(snapshot).toMatchSnapshot();
});
});import { renderToSnapshot } from 'inferno-test-utils';
import { Component } from 'inferno';
// Child components
function UserAvatar({ user }) {
return (
<div className="avatar">
<img src={user.avatar} alt={user.name} />
<span className="status" data-status={user.status}></span>
</div>
);
}
function UserInfo({ user }) {
return (
<div className="user-info">
<h3>{user.name}</h3>
<p>{user.email}</p>
<span className="role">{user.role}</span>
</div>
);
}
// Parent component
class UserCard extends Component {
render() {
const { user, showActions } = this.props;
return (
<div className="user-card">
<UserAvatar user={user} />
<UserInfo user={user} />
{showActions && (
<div className="actions">
<button className="btn-edit">Edit</button>
<button className="btn-delete">Delete</button>
</div>
)}
</div>
);
}
}
describe('UserCard', () => {
const mockUser = {
name: 'John Doe',
email: 'john@example.com',
role: 'Developer',
status: 'online',
avatar: 'avatar.jpg'
};
it('renders user card without actions', () => {
const snapshot = renderToSnapshot(
<UserCard user={mockUser} showActions={false} />
);
expect(snapshot).toMatchSnapshot();
});
it('renders user card with actions', () => {
const snapshot = renderToSnapshot(
<UserCard user={mockUser} showActions={true} />
);
expect(snapshot).toMatchSnapshot();
});
});import { renderToSnapshot } from 'inferno-test-utils';
function LoadingComponent({ isLoading, data, error }) {
if (error) {
return (
<div className="error">
<h3>Error occurred</h3>
<p>{error.message}</p>
<button>Retry</button>
</div>
);
}
if (isLoading) {
return (
<div className="loading">
<div className="spinner"></div>
<p>Loading...</p>
</div>
);
}
return (
<div className="data">
<h3>Data loaded</h3>
<ul>
{data.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
);
}
describe('LoadingComponent', () => {
it('renders loading state', () => {
const snapshot = renderToSnapshot(
<LoadingComponent isLoading={true} data={null} error={null} />
);
expect(snapshot).toMatchSnapshot();
});
it('renders error state', () => {
const error = { message: 'Failed to load data' };
const snapshot = renderToSnapshot(
<LoadingComponent isLoading={false} data={null} error={error} />
);
expect(snapshot).toMatchSnapshot();
});
it('renders data state', () => {
const data = [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' }
];
const snapshot = renderToSnapshot(
<LoadingComponent isLoading={false} data={data} error={null} />
);
expect(snapshot).toMatchSnapshot();
});
});interface InfernoSnapshot {
type: string;
props: Record<string, any>;
children: null | InfernoTestRendererNode[];
$$typeof?: symbol | string;
}
type InfernoTestRendererNode = InfernoSnapshot | string;The InfernoSnapshot interface represents the structure of snapshot objects created by the testing utilities:
import { vNodeToSnapshot } from 'inferno-test-utils';
const vnode = (
<div className="example" id="test">
<span>Text content</span>
<button disabled>Click me</button>
</div>
);
const snapshot = vNodeToSnapshot(vnode);
// Type: InfernoSnapshot
// {
// type: "div",
// props: { className: "example", id: "test" },
// children: [
// { type: "span", props: {}, children: ["Text content"] },
// { type: "button", props: { disabled: true }, children: ["Click me"] }
// ],
// $$typeof: Symbol(react.test.json)
// }import { renderToSnapshot } from 'inferno-test-utils';
function Button({ variant, size, disabled, children }) {
const className = `btn btn-${variant} btn-${size}`;
return (
<button className={className} disabled={disabled}>
{children}
</button>
);
}
describe('Button component', () => {
const testCases = [
{ variant: 'primary', size: 'large', disabled: false },
{ variant: 'secondary', size: 'medium', disabled: false },
{ variant: 'danger', size: 'small', disabled: true }
];
testCases.forEach(({ variant, size, disabled }) => {
it(`renders ${variant} ${size} button (disabled: ${disabled})`, () => {
const snapshot = renderToSnapshot(
<Button variant={variant} size={size} disabled={disabled}>
Test Button
</Button>
);
expect(snapshot).toMatchSnapshot();
});
});
});import { renderToSnapshot } from 'inferno-test-utils';
function ProductList({ products }) {
return (
<div className="product-list">
{products.map(product => (
<div key={product.id} className="product-item">
<h3>{product.name}</h3>
<p className="price">${product.price}</p>
<p className="description">{product.description}</p>
</div>
))}
</div>
);
}
describe('ProductList', () => {
it('renders empty list', () => {
const snapshot = renderToSnapshot(<ProductList products={[]} />);
expect(snapshot).toMatchSnapshot();
});
it('renders multiple products', () => {
const mockProducts = [
{ id: 1, name: 'Product 1', price: 10.99, description: 'Description 1' },
{ id: 2, name: 'Product 2', price: 15.99, description: 'Description 2' }
];
const snapshot = renderToSnapshot(<ProductList products={mockProducts} />);
expect(snapshot).toMatchSnapshot();
});
});The Jest integration utilities ensure that your Inferno components can be tested with the same snapshot testing workflow as React components, providing consistency across different component libraries.