data-client-react-testing
SKILL.md
Testing Patterns (@data-client/test)
Hook Testing with renderDataHook()
import { renderDataHook } from '@data-client/test';
it('useSuspense() should render the response', async () => {
const { result, waitFor } = renderDataHook(
() => useSuspense(ArticleResource.get, { id: 5 }),
{
initialFixtures: [
{
endpoint: ArticleResource.get,
args: [{ id: 5 }],
response: { id: 5, title: 'hi ho', content: 'whatever' },
},
],
},
);
expect(result.current.title).toBe('hi ho');
});
Options:
initialFixtures- Set up initial state of the storeresolverFixtures- Add interceptors for subsequent requestsgetInitialInterceptorData- Simulate changing server state
Return values:
- Inherits all
renderHook()return values from@testing-library/react controller- Controller instance for manual actionsallSettled()- Wait for all async operations to complete
Cleanup is automatic -- an afterEach hook is registered at module load time that drains all active cleanups. No manual renderDataHook.cleanup() calls are needed.
Fixtures and Interceptors
Success Fixture:
interface SuccessFixture {
endpoint;
args;
response;
error?;
delay?;
}
Response Interceptor:
interface ResponseInterceptor {
endpoint;
response(...args);
delay?;
delayCollapse?;
}
Testing Mutations
Create operations:
it('should create a new todo', async () => {
const { result } = renderDataHook(
() => useController(),
{
initialFixtures: [
{
endpoint: TodoResource.getList,
args: [],
response: [],
},
],
resolverFixtures: [
{
endpoint: TodoResource.getList.push,
response: (newTodo) => ({ ...newTodo, id: 1 }),
},
],
},
);
const newTodo = { title: 'Test Todo', completed: false };
const createdTodo = await result.current.fetch(TodoResource.getList.push, newTodo);
expect(createdTodo.id).toBe(1);
});
Testing Error States
it('should handle fetch errors', async () => {
const { result, waitFor } = renderDataHook(
() => useSuspense(TodoResource.get, { id: 1 }),
{
initialFixtures: [
{
endpoint: TodoResource.get,
args: [{ id: 1 }],
response: null,
error: new Error('Not found'),
},
],
},
);
await waitFor(() => {
expect(result.current).toBeUndefined();
});
});
Testing Components
Use MockResolver to provide fixture data when rendering components with DataProvider:
import { render } from '@testing-library/react';
import { DataProvider } from '@data-client/react';
import { MockResolver } from '@data-client/test';
it('should render todo list', async () => {
const fixtures = [
{
endpoint: TodoResource.getList,
args: [],
response: [{ id: 1, title: 'Test Todo', completed: false }],
},
];
const { getByText } = render(
<DataProvider>
<MockResolver fixtures={fixtures}>
<TodoList />
</MockResolver>
</DataProvider>,
);
expect(getByText('Test Todo')).toBeInTheDocument();
});
Testing with nock (HTTP Endpoint Testing)
import nock from 'nock';
it('should fetch data from API', async () => {
const scope = nock('https://jsonplaceholder.typicode.com')
.get('/todos/1')
.reply(200, { id: 1, title: 'Test', completed: false });
const result = await TodoResource.get({ id: 1 });
expect(result.title).toBe('Test');
scope.done();
});
Testing Managers
it('should handle manager middleware', async () => {
const mockManager = {
middleware: (controller) => (next) => async (action) => {
if (action.type === 'FETCH') {
console.log('Fetch action:', action);
}
return next(action);
},
cleanup: jest.fn(),
};
const { controller } = renderDataHook(
() => useController(),
{ managers: [mockManager] },
);
await controller.fetch(TodoResource.get, { id: 1 });
expect(mockManager.cleanup).not.toHaveBeenCalled();
});
Test File Organization
Keep tests under packages/*/src/**/__tests__:
packages/react/src/hooks/__tests__/useSuspense.test.ts
packages/react/src/components/__tests__/DataProvider.test.tsx
Test naming:
- Node-only:
*.node.test.ts[x] - React Native:
*.native.test.ts[x] - Regular:
*.test.ts[x]
Best Practices
- Use
renderDataHook()for testing hooks that use @data-client/react hooks - Use fixtures or interceptors when testing hooks or components
- Use
nockwhen testing networking definitions - Test both success and error scenarios
- Test mutations and their side effects
- Don't mock @data-client internals directly
- Don't use raw fetch in tests when fixtures are available
- Don't manually call
renderDataHook.cleanup()inafterEach-- cleanup is automatic
References
For detailed API documentation, see the references directory:
- renderDataHook - Hook testing utility
- makeRenderDataHook - Custom hook renderer
- Fixtures - Fixture format reference
- MockResolver - Component testing wrapper
- mockInitialState - Create initial state
- unit-testing-hooks - Hook testing guide
- unit-testing-components - Component testing guide
Weekly Installs
23
Repository
reactive/data-clientGitHub Stars
2.0K
First Seen
Feb 16, 2026
Security Audits
Installed on
opencode23
github-copilot23
codex23
kimi-cli23
gemini-cli23
cursor23