CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-inferno-test-utils

Suite of utilities for testing Inferno applications with comprehensive tree traversal, element finding, and Jest snapshot integration.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

jest-integration.mddocs/

Jest Integration API

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.

Snapshot Functions

vNodeToSnapshot

/**
 * 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): InfernoSnapshot

This 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)
// }

renderToSnapshot

/**
 * 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): InfernoSnapshot

This 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)
// }

Jest Integration Patterns

Basic Snapshot Testing

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();
  });
});

Component State Snapshots

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();
  });
});

Complex Component Hierarchies

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();
  });
});

Conditional Rendering Snapshots

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();
  });
});

Types and Interfaces

InfernoSnapshot

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:

  • type: The HTML tag name or component name as a string
  • props: All props passed to the element/component (excludes children)
  • children: Array of child snapshots or text content, null if no children
  • $$typeof: React test renderer compatibility symbol
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)
// }

Snapshot Testing Best Practices

Testing Props Variations

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();
    });
  });
});

Testing with Mock Data

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.

docs

index.md

jest-integration.md

rendering.md

tree-traversal.md

type-checking.md

tile.json