React-Admin Test Utilities
The `ra-test` package provides specialized utilities for efficiently testing applications built upon `react-admin`, a widely adopted frontend framework for developing administrative interfaces with React. As of early 2026, the current stable version of `react-admin` (and consequently `ra-test`, which is part of the same monorepo) is 5.14.6, characterized by a continuous release cadence with frequent minor updates and bug fixes. This library is specifically tailored to address the complexities of testing `react-admin` components, particularly custom views or logic that depend on the framework's intricate Redux store and React Router context. Unlike general React testing libraries, `ra-test` offers pre-configured wrappers like `TestContext` and helpers such as `renderWithRedux` that seamlessly provide the necessary `react-admin` environment, enabling developers to focus on the specific logic of their custom components rather than boilerplate setup. It differentiates itself by providing a robust, opinionated testing environment integrated deeply with `react-admin`'s architecture, making it easier to mock the `react-admin` state and dispatch actions for focused unit or integration tests within the ecosystem.
Common errors
-
Error: could not find react-redux context value; please ensure the component is wrapped in a <Provider>
cause `react-admin` components require a Redux store context, which `TestContext` provides, but this error indicates it's missing.fixEnsure the component under test is wrapped within `<TestContext>` or rendered using `renderWithRedux`. For example: `render(<TestContext><MyComponent /></TestContext>)` -
Error: useLocation() may be used only in the context of a <Router> component.
cause `react-admin` components often use React Router hooks, requiring a Router context that `TestContext` provides.fixThe component depending on `react-router` hooks or components must be rendered inside `TestContext`, which sets up the necessary `react-router` context. For example: `render(<TestContext><MyComponentThatUsesRouter /></TestContext>)` -
TypeError: Cannot read properties of undefined (reading 'dispatch') or TypeError: Cannot read property 'dispatch' of undefined
cause Attempting to spy on `store.dispatch` or interact with the Redux store when `TestContext` has not yet exposed it or when `enableReducers` is not set.fixIf spying on `dispatch`, ensure you use the render prop pattern for `TestContext` to access the `store` object: `<TestContext>{({ store }) => { dispatchSpy = jest.spyOn(store, 'dispatch'); return <MyComponent />; }}</TestContext>`. Also, ensure `enableReducers` is set if state changes are expected.
Warnings
- breaking The `ra-test` package versions are tightly coupled with the major versions of `react-admin`. Using `ra-test@3.x.x` with `react-admin@4.x.x` or `5.x.x` will lead to incompatible APIs and runtime errors due to significant changes in `react-admin`'s internal structure and context providers.
- gotcha Direct unit testing of most `react-admin`'s built-in components is generally discouraged by the framework maintainers. `ra-test` is primarily for custom components that integrate with `react-admin`'s context, rather than testing react-admin's internals.
- gotcha `react-admin` components heavily rely on React Context for Redux, React Router, and internal framework state. Without wrapping components under test in `TestContext` (or `renderWithRedux`), they will fail to initialize or function correctly.
- deprecated The use of `TestContext` without `enableReducers` will prevent Redux actions from being processed, making tests for components that dispatch actions ineffective. While not strictly deprecated, it's a common oversight.
Install
-
npm install ra-test -
yarn add ra-test -
pnpm add ra-test
Imports
- TestContext
const { TestContext } = require('ra-test');import { TestContext } from 'ra-test'; - renderWithRedux
import renderWithRedux from 'ra-test';
import { renderWithRedux } from 'ra-test'; - defaultStore
import { defaultStore } from 'ra-test';
Quickstart
import * as React from "react";
import { TestContext } from 'ra-test';
import { render, fireEvent, screen } from '@testing-library/react';
// Imagine this is your custom react-admin Edit view component
const MyCustomEditView = ({ basePath, id, resource }) => {
const handleClick = () => {
// In a real app, this might dispatch an action or navigate
console.log(`Action for resource ${resource} with ID ${id} at ${basePath}`);
};
return (
<div data-testid="my-custom-edit-view">
<h1>Edit {resource} #{id}</h1>
<p>Base Path: {basePath}</p>
<button onClick={handleClick}>Perform Action</button>
</div>
);
};
describe('MyCustomEditView', () => {
const defaultEditProps = {
basePath: '/posts',
id: '123',
resource: 'posts',
};
it('should render the custom edit view with provided props', () => {
render(
<TestContext enableReducers>
<MyCustomEditView {...defaultEditProps} />
</TestContext>
);
expect(screen.getByText('Edit posts #123')).toBeInTheDocument();
expect(screen.getByText('Base Path: /posts')).toBeInTheDocument();
});
it('should simulate a button click', () => {
const consoleSpy = jest.spyOn(console, 'log');
render(
<TestContext enableReducers>
<MyCustomEditView {...defaultEditProps} />
</TestContext>
);
fireEvent.click(screen.getByText('Perform Action'));
expect(consoleSpy).toHaveBeenCalledWith('Action for resource posts with ID 123 at /posts');
consoleSpy.mockRestore();
});
});