or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-react-hooks-testing-library

Simple and complete React hooks testing utilities that encourage good testing practices.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/react-hooks-testing-library@0.6.x

To install, run

npx @tessl/cli install tessl/npm-react-hooks-testing-library@0.6.0

index.mddocs/

React Hooks Testing Library

React Hooks Testing Library provides simple and complete React hooks testing utilities that encourage good testing practices. It allows you to create a simple test harness for React hooks that handles running them within the body of a function component, providing various utility functions for updating inputs and retrieving outputs of custom hooks.

Package Information

  • Package Name: react-hooks-testing-library
  • Package Type: npm
  • Language: JavaScript with TypeScript definitions
  • Installation: npm install --save-dev react-hooks-testing-library

Dependencies:

  • react (peer dependency, ^16.8.0)
  • react-test-renderer (peer dependency, ^16.8.0)

Core Imports

import { renderHook, act } from "react-hooks-testing-library";
// testHook is also available but deprecated - use renderHook instead

For CommonJS:

const { renderHook, act } = require("react-hooks-testing-library");
// testHook is also available but deprecated - use renderHook instead

Basic Usage

import { renderHook, act } from "react-hooks-testing-library";
import { useState, useCallback } from "react";

// Example custom hook
function useCounter() {
  const [count, setCount] = useState(0);
  const increment = useCallback(() => setCount((x) => x + 1), []);
  const decrement = useCallback(() => setCount((x) => x - 1), []);
  return { count, increment, decrement };
}

// Test the hook
test("should increment counter", () => {
  const { result } = renderHook(() => useCounter());
  
  act(() => result.current.increment());
  
  expect(result.current.count).toBe(1);
});

// Test with async operations
test("should handle async updates", async () => {
  const { result, waitForNextUpdate } = renderHook(() => useAsyncHook());
  
  expect(result.current.loading).toBe(true);
  
  await waitForNextUpdate();
  
  expect(result.current.loading).toBe(false);
});

Capabilities

Hook Rendering

Renders a test component that calls the provided hook callback every time it renders.

/**
 * Renders a test component that calls the provided callback, including any hooks it calls
 * @param callback - Function to call each render that should call one or more hooks for testing
 * @param options - Optional configuration object
 * @returns Object with result, utilities for testing async hooks, rerendering, and unmounting
 */
function renderHook<P, R>(
  callback: (props: P) => R,
  options?: {
    initialProps?: P;
    wrapper?: React.ComponentType;
  }
): {
  readonly result: {
    readonly current: R;
    readonly error: Error;
  };
  readonly waitForNextUpdate: () => Promise<void>;
  readonly unmount: () => boolean;
  readonly rerender: (hookProps?: P) => void;
};

Usage Examples:

// Basic hook testing
const { result } = renderHook(() => useState(0));
expect(result.current[0]).toBe(0);

// Testing hooks with props
const { result, rerender } = renderHook(
  ({ initialCount }) => useState(initialCount),
  { initialProps: { initialCount: 5 } }
);
expect(result.current[0]).toBe(5);

// Rerender with new props
rerender({ initialCount: 10 });
expect(result.current[0]).toBe(5); // State is preserved, initialCount only used on first render

// Testing hooks that require context
const wrapper = ({ children }) => (
  <ThemeProvider theme="dark">{children}</ThemeProvider>
);
const { result } = renderHook(() => useTheme(), { wrapper });
expect(result.current.theme).toBe("dark");

State Updates and Effects

Wrapper around react-test-renderer's act function for handling state updates and effects.

/**
 * Ensures that updates related to state changes, effects, and event handlers are properly flushed
 * @param callback - Function to execute within act scope
 * @returns void
 */
function act(callback: () => void): void;

Usage Examples:

// Wrapping state updates
const { result } = renderHook(() => useCounter());

act(() => {
  result.current.increment();
});

expect(result.current.count).toBe(1);

// Multiple state updates
act(() => {
  result.current.increment();
  result.current.increment();
});

expect(result.current.count).toBe(3);

Async Hook Testing

Handle asynchronous operations in hooks with proper waiting mechanisms.

/**
 * Returns a Promise that resolves the next time the hook renders
 * Commonly used when state is updated as the result of an asynchronous action
 * @returns Promise that resolves on next hook render
 */
waitForNextUpdate(): Promise<void>;

Usage Examples:

// Testing async hooks
const useAsyncData = () => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    fetchData().then((result) => {
      setData(result);
      setLoading(false);
    });
  }, []);
  
  return { data, loading };
};

test("should load data asynchronously", async () => {
  const { result, waitForNextUpdate } = renderHook(() => useAsyncData());
  
  expect(result.current.loading).toBe(true);
  expect(result.current.data).toBe(null);
  
  await waitForNextUpdate();
  
  expect(result.current.loading).toBe(false);
  expect(result.current.data).toBeDefined();
});

Hook Re-rendering

Re-render the hook with new props to test how it responds to prop changes.

/**
 * Function to rerender the test component including any hooks called in the callback function
 * @param newProps - New props to pass to the callback function for future renders
 * @returns void
 */
rerender(newProps?: P): void;

Usage Examples:

// Testing prop changes
const useGreeting = (name) => {
  return `Hello, ${name}!`;
};

const { result, rerender } = renderHook(
  ({ name }) => useGreeting(name),
  { initialProps: { name: "Alice" } }
);

expect(result.current).toBe("Hello, Alice!");

rerender({ name: "Bob" });
expect(result.current).toBe("Hello, Bob!");

Hook Cleanup

Unmount the test component to trigger cleanup effects for useEffect hooks.

/**
 * Function to unmount the test component
 * Commonly used to trigger cleanup effects for useEffect hooks
 * @returns boolean indicating if unmount was successful
 */
unmount(): boolean;

Usage Examples:

// Testing cleanup effects
const useTimer = () => {
  const [count, setCount] = useState(0);
  
  useEffect(() => {
    const timer = setInterval(() => {
      setCount((c) => c + 1);
    }, 1000);
    
    return () => clearInterval(timer);
  }, []);
  
  return count;
};

test("should cleanup timer on unmount", () => {
  const { unmount } = renderHook(() => useTimer());
  
  // Verify cleanup doesn't throw errors
  expect(() => unmount()).not.toThrow();
});

Error Handling

Access errors thrown during hook execution for testing error scenarios.

/**
 * Access to any error thrown during hook execution
 */
interface HookResult<R> {
  readonly result: {
    readonly current: R;
    readonly error: Error;
  };
}

Usage Examples:

// Testing hook errors
const useErrorProneHook = (shouldThrow) => {
  if (shouldThrow) {
    throw new Error("Something went wrong");
  }
  return "success";
};

test("should capture hook errors", () => {
  const { result } = renderHook(
    ({ shouldThrow }) => useErrorProneHook(shouldThrow),
    { initialProps: { shouldThrow: true } }
  );
  
  expect(result.error).toBeInstanceOf(Error);
  expect(result.error.message).toBe("Something went wrong");
});

Types

/**
 * Options for configuring hook rendering
 */
interface RenderHookOptions<P> {
  /** Initial props passed to the hook callback */
  initialProps?: P;
  /** React component to wrap around the rendered hook */
  wrapper?: React.ComponentType;
}

/**
 * Result object returned by renderHook
 */
interface RenderHookResult<P, R> {
  /** Container for hook return value and any errors */
  readonly result: {
    /** Current return value of the hook callback */
    readonly current: R;
    /** Error thrown during hook execution, if any */
    readonly error: Error;
  };
  /** Promise that resolves on next hook render */
  readonly waitForNextUpdate: () => Promise<void>;
  /** Function to unmount the test component */
  readonly unmount: () => boolean;
  /** Function to rerender with optional new props */
  readonly rerender: (hookProps?: P) => void;
}

Deprecated APIs

testHook (Deprecated)

/**
 * @deprecated Use renderHook instead. Will be removed in a future version.
 * Legacy alias for renderHook function
 */
const testHook: typeof renderHook;

The testHook function is deprecated and shows a console warning. Use renderHook instead for all new code.